diff --git a/Directory.Packages.props b/Directory.Packages.props index 118112abbc0..5f2a448ca56 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -110,8 +110,8 @@ - - + + diff --git a/eng/Signing.props b/eng/Signing.props index 3400bb5677b..af6596f2879 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -51,7 +51,10 @@ + + + diff --git a/eng/Versions.props b/eng/Versions.props index d3c397ec9b3..eada7ba1557 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -39,7 +39,7 @@ 10.0.0-beta.26123.2 10.0.0-beta.26123.2 10.0.0-beta.26123.2 - 10.0.2 + 10.0.3 10.2.0 10.1.0-preview.1.25608.1 @@ -65,35 +65,35 @@ - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 - 10.0.2 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 + 10.0.3 diff --git a/extension/loc/xlf/aspire-vscode.xlf b/extension/loc/xlf/aspire-vscode.xlf index ea53f379a7f..935b07ee76f 100644 --- a/extension/loc/xlf/aspire-vscode.xlf +++ b/extension/loc/xlf/aspire-vscode.xlf @@ -61,6 +61,9 @@ C# support is not enabled in this workspace. This project should have started through the Aspire CLI. + + Close the dashboard browser when the debug session ends. Works with debug browser options (Chrome, Edge, Firefox). + Codespaces @@ -190,6 +193,15 @@ Launch Aspire Dashboard + + Launch Chrome as a debug session (auto-closes when debugging ends). + + + Launch Firefox as a debug session (requires Firefox Debugger extension). + + + Launch Microsoft Edge as a debug session (auto-closes when debugging ends). + Launch the effective Aspire apphost in your workspace @@ -307,6 +319,9 @@ The apphost is not compatible. Consider upgrading the apphost or Aspire CLI. + + The browser to use when auto-launching the Aspire Dashboard. + The path to the Aspire CLI executable. If not set, the extension will attempt to use 'aspire' from the system PATH. @@ -319,6 +334,9 @@ Update integrations + + Use the system default browser (cannot auto-close). + View logs diff --git a/extension/package.json b/extension/package.json index 3744fb344c8..8a1b9392351 100644 --- a/extension/package.json +++ b/extension/package.json @@ -29,7 +29,10 @@ "onDebugDynamicConfigurations:aspire", "workspaceContains:**/*.csproj", "onView:workbench.view.debug", - "workspaceContains:**/apphost.cs" + "workspaceContains:**/apphost.cs", + "onCommand:aspire-vscode.installCliStable", + "onCommand:aspire-vscode.installCliDaily", + "onCommand:aspire-vscode.verifyCliInstalled" ], "main": "./dist/extension.js", "l10n": "./l10n", @@ -234,6 +237,21 @@ "title": "%command.executeResourceCommand%", "category": "Aspire", "icon": "$(terminal)" + }, + { + "command": "aspire-vscode.installCliStable", + "title": "%command.installCliStable%", + "category": "Aspire" + }, + { + "command": "aspire-vscode.installCliDaily", + "title": "%command.installCliDaily%", + "category": "Aspire" + }, + { + "command": "aspire-vscode.verifyCliInstalled", + "title": "%command.verifyCliInstalled%", + "category": "Aspire" } ], "jsonValidation": [ @@ -403,6 +421,25 @@ "description": "%configuration.aspire.enableAspireDashboardAutoLaunch%", "scope": "window" }, + "aspire.dashboardBrowser": { + "type": "string", + "enum": ["openExternalBrowser", "debugChrome", "debugEdge", "debugFirefox"], + "default": "openExternalBrowser", + "description": "%configuration.aspire.dashboardBrowser%", + "enumDescriptions": [ + "%configuration.aspire.dashboardBrowser.openExternalBrowser%", + "%configuration.aspire.dashboardBrowser.debugChrome%", + "%configuration.aspire.dashboardBrowser.debugEdge%", + "%configuration.aspire.dashboardBrowser.debugFirefox%" + ], + "scope": "window" + }, + "aspire.closeDashboardOnDebugEnd": { + "type": "boolean", + "default": true, + "description": "%configuration.aspire.closeDashboardOnDebugEnd%", + "scope": "window" + }, "aspire.enableDebugConfigEnvironmentLogging": { "type": "boolean", "default": true, @@ -410,7 +447,77 @@ "scope": "window" } } - } + }, + "walkthroughs": [ + { + "id": "aspire-vscode.getStarted", + "title": "%walkthrough.getStarted.title%", + "description": "%walkthrough.getStarted.description%", + "steps": [ + { + "id": "aspire-vscode.getStarted.welcome", + "title": "%walkthrough.getStarted.welcome.title%", + "description": "%walkthrough.getStarted.welcome.description%", + "media": { + "markdown": "walkthrough/welcome.md" + } + }, + { + "id": "aspire-vscode.getStarted.installCli", + "title": "%walkthrough.getStarted.installCli.title%", + "description": "%walkthrough.getStarted.installCli.description%", + "media": { + "markdown": "walkthrough/installCli.md" + }, + "completionEvents": [ + "onCommand:aspire-vscode.verifyCliInstalled" + ] + }, + { + "id": "aspire-vscode.getStarted.createProject", + "title": "%walkthrough.getStarted.createProject.title%", + "description": "%walkthrough.getStarted.createProject.description%", + "media": { + "markdown": "walkthrough/createProject.md" + }, + "completionEvents": [ + "onCommand:aspire-vscode.new" + ] + }, + { + "id": "aspire-vscode.getStarted.runApp", + "title": "%walkthrough.getStarted.runApp.title%", + "description": "%walkthrough.getStarted.runApp.description%", + "media": { + "markdown": "walkthrough/runApp.md" + }, + "completionEvents": [ + "onCommand:aspire-vscode.runAppHost", + "onCommand:aspire-vscode.debugAppHost" + ] + }, + { + "id": "aspire-vscode.getStarted.dashboard", + "title": "%walkthrough.getStarted.dashboard.title%", + "description": "%walkthrough.getStarted.dashboard.description%", + "media": { + "markdown": "walkthrough/dashboard.md" + }, + "completionEvents": [ + "onCommand:aspire-vscode.openDashboard" + ] + }, + { + "id": "aspire-vscode.getStarted.nextSteps", + "title": "%walkthrough.getStarted.nextSteps.title%", + "description": "%walkthrough.getStarted.nextSteps.description%", + "media": { + "markdown": "walkthrough/nextSteps.md" + } + } + ] + } + ] }, "repository": { "type": "git", diff --git a/extension/package.nls.json b/extension/package.nls.json index e5eb3ee8891..55197b32c1f 100644 --- a/extension/package.nls.json +++ b/extension/package.nls.json @@ -22,6 +22,12 @@ "configuration.aspire.enableAspireCliDebugLogging": "Enable console debug logging for Aspire CLI commands executed by the extension.", "configuration.aspire.enableAspireDcpDebugLogging": "Enable Developer Control Plane (DCP) debug logging for Aspire applications. Logs will be stored in the workspace's .aspire/dcp/logs-{debugSessionId} folder.", "configuration.aspire.enableAspireDashboardAutoLaunch": "Enable automatic launch of the Aspire Dashboard when using the Aspire debugger.", + "configuration.aspire.dashboardBrowser": "The browser to use when auto-launching the Aspire Dashboard.", + "configuration.aspire.dashboardBrowser.openExternalBrowser": "Use the system default browser (cannot auto-close).", + "configuration.aspire.dashboardBrowser.debugChrome": "Launch Chrome as a debug session (auto-closes when debugging ends).", + "configuration.aspire.dashboardBrowser.debugEdge": "Launch Microsoft Edge as a debug session (auto-closes when debugging ends).", + "configuration.aspire.dashboardBrowser.debugFirefox": "Launch Firefox as a debug session (requires Firefox Debugger extension).", + "configuration.aspire.closeDashboardOnDebugEnd": "Close the dashboard browser when the debug session ends. Works with debug browser options (Chrome, Edge, Firefox).", "configuration.aspire.enableDebugConfigEnvironmentLogging": "Include environment variables when logging debug session configurations. This can help diagnose environment-related issues but may expose sensitive information in logs.", "command.runAppHost": "Run Aspire apphost", "command.debugAppHost": "Debug Aspire apphost", @@ -119,5 +125,22 @@ "command.startResource": "Start", "command.restartResource": "Restart", "command.viewResourceLogs": "View logs", - "command.executeResourceCommand": "Execute resource command" + "command.executeResourceCommand": "Execute resource command", + "command.installCliStable": "Install Aspire CLI (stable)", + "command.installCliDaily": "Install Aspire CLI (daily)", + "command.verifyCliInstalled": "Verify Aspire CLI installation", + "walkthrough.getStarted.title": "Get started with Aspire", + "walkthrough.getStarted.description": "Learn how to create, run, and monitor distributed applications with Aspire.", + "walkthrough.getStarted.welcome.title": "Welcome to Aspire", + "walkthrough.getStarted.welcome.description": "Aspire helps you build observable, production-ready distributed apps — orchestrating front ends, APIs, containers, and databases from code.\n\nIt works with **any language**: C#, Python, JavaScript, Go, Java, and more.", + "walkthrough.getStarted.installCli.title": "Install the Aspire CLI", + "walkthrough.getStarted.installCli.description": "The Aspire CLI creates, runs, and manages your applications. Install it using the commands in the panel, then verify your installation.\n\n[Verify installation](command:aspire-vscode.verifyCliInstalled)", + "walkthrough.getStarted.createProject.title": "Create a new project", + "walkthrough.getStarted.createProject.description": "Scaffold a new Aspire project from a starter template. The template includes an apphost orchestrator, a sample API, and a web frontend.\n\n[Create new project](command:aspire-vscode.new)", + "walkthrough.getStarted.runApp.title": "Run your app", + "walkthrough.getStarted.runApp.description": "Start your Aspire app to launch all services and open the real-time dashboard.\n\n[Run apphost](command:aspire-vscode.runAppHost)\n\n[Debug apphost](command:aspire-vscode.debugAppHost)", + "walkthrough.getStarted.dashboard.title": "Explore the dashboard", + "walkthrough.getStarted.dashboard.description": "The Aspire Dashboard shows your resources, endpoints, logs, traces, and metrics — all in one place.\n\n[Open dashboard](command:aspire-vscode.openDashboard)", + "walkthrough.getStarted.nextSteps.title": "Next steps", + "walkthrough.getStarted.nextSteps.description": "You're all set! Add integrations for databases, messaging, and cloud services, or deploy your app to production.\n\n[Add an integration](command:aspire-vscode.add)\n\n[Open Aspire docs](https://aspire.dev/docs/)" } diff --git a/extension/resources/aspire-dashboard-dark.png b/extension/resources/aspire-dashboard-dark.png new file mode 100644 index 00000000000..b582a735e5b Binary files /dev/null and b/extension/resources/aspire-dashboard-dark.png differ diff --git a/extension/src/commands/walkthroughCommands.ts b/extension/src/commands/walkthroughCommands.ts new file mode 100644 index 00000000000..af1161ee7dc --- /dev/null +++ b/extension/src/commands/walkthroughCommands.ts @@ -0,0 +1,36 @@ +import * as vscode from 'vscode'; +import { aspireTerminalName } from '../loc/strings'; + +function getOrCreateTerminal(): vscode.Terminal { + const existing = vscode.window.terminals.find(t => t.name === aspireTerminalName); + if (existing) { + return existing; + } + return vscode.window.createTerminal({ name: aspireTerminalName }); +} + +function runInTerminal(command: string): void { + const terminal = getOrCreateTerminal(); + terminal.show(); + terminal.sendText(command); +} + +export async function installCliStableCommand(): Promise { + if (process.platform === 'win32') { + runInTerminal('irm https://aspire.dev/install.ps1 | iex'); + } else { + runInTerminal('curl -sSL https://aspire.dev/install.sh | bash'); + } +} + +export async function installCliDailyCommand(): Promise { + if (process.platform === 'win32') { + runInTerminal('iex "& { $(irm https://aspire.dev/install.ps1) } -Quality dev"'); + } else { + runInTerminal('curl -sSL https://aspire.dev/install.sh | bash -s -- -q dev'); + } +} + +export async function verifyCliInstalledCommand(): Promise { + runInTerminal('aspire --version'); +} diff --git a/extension/src/debugger/AspireDebugSession.ts b/extension/src/debugger/AspireDebugSession.ts index 434eb0cf793..5a0f340bbac 100644 --- a/extension/src/debugger/AspireDebugSession.ts +++ b/extension/src/debugger/AspireDebugSession.ts @@ -6,15 +6,18 @@ import { AspireResourceExtendedDebugConfiguration, AspireResourceDebugSession, E import { extensionLogOutputChannel } from "../utils/logging"; import AspireDcpServer, { generateDcpIdPrefix } from "../dcp/AspireDcpServer"; import { spawnCliProcess } from "./languages/cli"; -import { disconnectingFromSession, launchingWithAppHost, launchingWithDirectory, processExceptionOccurred, processExitedWithCode } from "../loc/strings"; +import { disconnectingFromSession, launchingWithAppHost, launchingWithDirectory, processExceptionOccurred, processExitedWithCode, aspireDashboard } from "../loc/strings"; import { projectDebuggerExtension } from "./languages/dotnet"; import AspireRpcServer from "../server/AspireRpcServer"; import { createDebugSessionConfiguration } from "./debuggerExtensions"; import { AspireTerminalProvider } from "../utils/AspireTerminalProvider"; import { ICliRpcClient } from "../server/rpcClient"; import path from "path"; +import os from "os"; import { EnvironmentVariables } from "../utils/environment"; +export type DashboardBrowserType = 'openExternalBrowser' | 'debugChrome' | 'debugEdge' | 'debugFirefox'; + export class AspireDebugSession implements vscode.DebugAdapter { private readonly _onDidSendMessage = new EventEmitter(); private _messageSeq = 1; @@ -28,6 +31,7 @@ export class AspireDebugSession implements vscode.DebugAdapter { private _resourceDebugSessions: AspireResourceDebugSession[] = []; private _trackedDebugAdapters: string[] = []; private _rpcClient?: ICliRpcClient; + private _dashboardDebugSession: vscode.DebugSession | null = null; private readonly _disposables: vscode.Disposable[] = []; private _disposed = false; private _userInitiatedStop = false; @@ -291,6 +295,79 @@ export class AspireDebugSession implements vscode.DebugAdapter { }); } + /** + * Opens the dashboard URL in the specified browser. + * For debugChrome/debugEdge/debugFirefox, launches as a child debug session that auto-closes with the Aspire debug session. + */ + async openDashboard(url: string, browserType: DashboardBrowserType): Promise { + extensionLogOutputChannel.info(`Opening dashboard in browser: ${browserType}, URL: ${url}`); + + switch (browserType) { + case 'debugChrome': + await this.launchDebugBrowser(url, 'pwa-chrome'); + break; + + case 'debugEdge': + await this.launchDebugBrowser(url, 'pwa-msedge'); + break; + + case 'debugFirefox': + await this.launchDebugBrowser(url, 'firefox'); + break; + + case 'openExternalBrowser': + default: + // Use VS Code's default external browser handling + await vscode.env.openExternal(vscode.Uri.parse(url)); + break; + } + } + + /** + * Launches a browser as a child debug session. + * The browser will automatically close when the parent Aspire debug session ends. + */ + private async launchDebugBrowser(url: string, debugType: 'pwa-chrome' | 'pwa-msedge' | 'firefox'): Promise { + const debugConfig: vscode.DebugConfiguration = { + type: debugType, + name: aspireDashboard, + request: 'launch', + url: url, + }; + + // Add type-specific options + if (debugType === 'pwa-chrome' || debugType === 'pwa-msedge') { + // Don't pause on entry for Chrome/Edge + debugConfig.pauseForSourceMap = false; + } + else if (debugType === 'firefox') { + // Firefox debugger requires webRoot; resolve to actual workspace path + debugConfig.webRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? os.tmpdir(); + debugConfig.pathMappings = []; + } + + // Register listener before starting so we don't miss the event + const disposable = vscode.debug.onDidStartDebugSession((session) => { + if (session.configuration.name === aspireDashboard && session.type === debugType) { + this._dashboardDebugSession = session; + disposable.dispose(); + } + }); + + // Start as a child debug session - it will close when parent closes + const didStart = await vscode.debug.startDebugging( + undefined, + debugConfig, + this._session + ); + + if (!didStart) { + disposable.dispose(); + extensionLogOutputChannel.warn(`Failed to start debug browser (${debugType}), falling back to default browser`); + await vscode.env.openExternal(vscode.Uri.parse(url)); + } + } + dispose(): void { if (this._disposed) { return; @@ -302,6 +379,36 @@ export class AspireDebugSession implements vscode.DebugAdapter { this._trackedDebugAdapters = []; } + /** + * Closes the dashboard browser if closeDashboardOnDebugEnd is enabled. + * Handles closing debug browser sessions. + */ + private closeDashboard(): void { + const aspireConfig = vscode.workspace.getConfiguration('aspire'); + const shouldClose = aspireConfig.get('closeDashboardOnDebugEnd', true); + + if (!shouldClose) { + this._dashboardDebugSession = null; + return; + } + + extensionLogOutputChannel.info('Closing dashboard browser...'); + + // For debug browsers, stop the debug session + if (this._dashboardDebugSession) { + vscode.debug.stopDebugging(this._dashboardDebugSession).then( + () => extensionLogOutputChannel.info('Dashboard debug session stopped.'), + (err) => extensionLogOutputChannel.warn(`Failed to stop dashboard debug session: ${err}`) + ); + this._dashboardDebugSession = null; + return; + } + // At this point there is no tracked dashboard debug session to stop. + // Any debug browser child sessions (debugChrome, debugEdge, debugFirefox) will + // automatically close when the parent Aspire session is stopped, so no further + // cleanup is required here. + } + private sendResponse(request: any, body: any = {}) { this._onDidSendMessage.fire({ type: 'response', diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 2e159fcc92b..085d27b6516 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -26,6 +26,7 @@ import { openLocalSettingsCommand, openGlobalSettingsCommand } from './commands/ import { checkCliAvailableOrRedirect, checkForExistingAppHostPathInWorkspace } from './utils/workspace'; import { AspireEditorCommandProvider } from './editor/AspireEditorCommandProvider'; import { AspireAppHostTreeProvider } from './views/AspireAppHostTreeProvider'; +import { installCliStableCommand, installCliDailyCommand, verifyCliInstalledCommand } from './commands/walkthroughCommands'; import { AspireStatusBarProvider } from './views/AspireStatusBarProvider'; let aspireExtensionContext = new AspireExtensionContext(); @@ -68,6 +69,11 @@ export async function activate(context: vscode.ExtensionContext) { const runAppHostCommandRegistration = vscode.commands.registerCommand('aspire-vscode.runAppHost', () => editorCommandProvider.tryExecuteRunAppHost(true)); const debugAppHostCommandRegistration = vscode.commands.registerCommand('aspire-vscode.debugAppHost', () => editorCommandProvider.tryExecuteRunAppHost(false)); + // Walkthrough commands (no CLI check - CLI may not be installed yet) + const installCliStableRegistration = vscode.commands.registerCommand('aspire-vscode.installCliStable', installCliStableCommand); + const installCliDailyRegistration = vscode.commands.registerCommand('aspire-vscode.installCliDaily', installCliDailyCommand); + const verifyCliInstalledRegistration = vscode.commands.registerCommand('aspire-vscode.verifyCliInstalled', verifyCliInstalledCommand); + // Aspire panel - running app hosts tree view const appHostTreeProvider = new AspireAppHostTreeProvider(terminalProvider); const appHostTreeView = vscode.window.createTreeView('aspire-vscode.runningAppHosts', { @@ -97,6 +103,7 @@ export async function activate(context: vscode.ExtensionContext) { context.subscriptions.push(cliAddCommandRegistration, cliNewCommandRegistration, cliInitCommandRegistration, cliDeployCommandRegistration, cliPublishCommandRegistration, openTerminalCommandRegistration, configureLaunchJsonCommandRegistration); context.subscriptions.push(cliUpdateCommandRegistration, cliUpdateSelfCommandRegistration, settingsCommandRegistration, openLocalSettingsCommandRegistration, openGlobalSettingsCommandRegistration, runAppHostCommandRegistration, debugAppHostCommandRegistration); + context.subscriptions.push(installCliStableRegistration, installCliDailyRegistration, verifyCliInstalledRegistration); const debugConfigProvider = new AspireDebugConfigurationProvider(); context.subscriptions.push( diff --git a/extension/src/loc/strings.ts b/extension/src/loc/strings.ts index 44d743af0d9..78045a3d6fc 100644 --- a/extension/src/loc/strings.ts +++ b/extension/src/loc/strings.ts @@ -9,6 +9,7 @@ export const codespacesUrl = (url: string) => vscode.l10n.t('Codespaces: {0}', u export const directLink = vscode.l10n.t('Open local URL'); export const codespacesLink = vscode.l10n.t('Open codespaces URL'); export const openAspireDashboard = vscode.l10n.t('Launch Aspire Dashboard'); +export const aspireDashboard = vscode.l10n.t('Aspire Dashboard'); export const noWorkspaceOpen = vscode.l10n.t('No workspace is open. Please open a folder or workspace before running this command.'); export const failedToShowPromptEmpty = vscode.l10n.t('Failed to show prompt, text was empty.'); export const rpcServerAddressError = vscode.l10n.t('Failed to get RPC server address. The extension may not function correctly.'); diff --git a/extension/src/server/interactionService.ts b/extension/src/server/interactionService.ts index 57379e71087..6f8f2abf9c3 100644 --- a/extension/src/server/interactionService.ts +++ b/extension/src/server/interactionService.ts @@ -8,7 +8,7 @@ import { ProgressNotifier } from './progressNotifier'; import { applyTextStyle, formatText } from '../utils/strings'; import { extensionLogOutputChannel } from '../utils/logging'; import { AspireExtendedDebugConfiguration, EnvVar } from '../dcp/types'; -import { AspireDebugSession } from '../debugger/AspireDebugSession'; +import { AspireDebugSession, DashboardBrowserType } from '../debugger/AspireDebugSession'; import { AnsiColors } from '../utils/AspireTerminalProvider'; import { isDirectory } from '../utils/io'; @@ -34,6 +34,7 @@ export interface IInteractionService { logMessage: (logLevel: CSLogLevel, message: string) => void; launchAppHost(projectFile: string, args: string[], environment: EnvVar[], debug: boolean): Promise; stopDebugging: () => void; + closeDashboard: () => void; notifyAppHostStartupCompleted: () => void; startDebugSession: (workingDirectory: string, projectFile: string | null, debug: boolean) => Promise; writeDebugSessionMessage: (message: string, stdout: boolean, textStyle?: string) => void; @@ -328,11 +329,16 @@ export class InteractionService implements IInteractionService { // If aspire.enableAspireDashboardAutoLaunch is true, the dashboard will be launched automatically and we do not need // to show an information message. - const enableDashboardAutoLaunch = vscode.workspace.getConfiguration('aspire').get('enableAspireDashboardAutoLaunch', true); + const aspireConfig = vscode.workspace.getConfiguration('aspire'); + const enableDashboardAutoLaunch = aspireConfig.get('enableAspireDashboardAutoLaunch', true); if (enableDashboardAutoLaunch) { - // Open the dashboard URL in an external browser. Prefer codespaces URL if available. + // Open the dashboard URL in the configured browser. Prefer codespaces URL if available. const urlToOpen = codespacesUrl || baseUrl; - vscode.env.openExternal(vscode.Uri.parse(urlToOpen)); + const debugSession = this._getAspireDebugSession(); + if (debugSession) { + const browserType = aspireConfig.get('dashboardBrowser', 'openExternalBrowser'); + await debugSession.openDashboard(urlToOpen, browserType); + } return; } @@ -481,6 +487,13 @@ export class InteractionService implements IInteractionService { clearProgressNotification() { this._progressNotifier.clear(); } + + /** + * Closes the dashboard browser. Delegates to the current AspireDebugSession. + */ + closeDashboard(): void { + // No-op when called from InteractionService - the debug session handles closing in dispose() + } } function tryExecuteEndpoint(interactionService: IInteractionService, withAuthentication: (callback: (...params: any[]) => any) => (...params: any[]) => any) { diff --git a/extension/src/views/AspireAppHostTreeProvider.ts b/extension/src/views/AspireAppHostTreeProvider.ts index 5178b99e7bc..030e6b9858a 100644 --- a/extension/src/views/AspireAppHostTreeProvider.ts +++ b/extension/src/views/AspireAppHostTreeProvider.ts @@ -93,13 +93,13 @@ class ResourceItem extends vscode.TreeItem { function getResourceContextValue(resource: ResourceJson): string { const commands = resource.commands ? Object.keys(resource.commands) : []; const parts = ['resource']; - if (commands.includes('resource-start')) { + if (commands.includes('start') || commands.includes('resource-start')) { parts.push('canStart'); } - if (commands.includes('resource-stop')) { + if (commands.includes('stop') || commands.includes('resource-stop')) { parts.push('canStop'); } - if (commands.includes('resource-restart')) { + if (commands.includes('restart') || commands.includes('resource-restart')) { parts.push('canRestart'); } return parts.join(':'); @@ -314,7 +314,7 @@ export class AspireAppHostTreeProvider implements vscode.TreeDataProvider 0 ? ` ${extraArgs.join(' ')}` : ''; - this._terminalProvider.sendAspireCommandToAspireTerminal(`${command} "${element.resource.name}" --apphost "${appHost.appHostPath}"${suffix}`); + this._terminalProvider.sendAspireCommandToAspireTerminal(`resource "${element.resource.name}" ${command} --apphost "${appHost.appHostPath}"${suffix}`); } private _findAppHostForResource(element: ResourceItem): AppHostDisplayInfo | undefined { diff --git a/extension/walkthrough/createProject.md b/extension/walkthrough/createProject.md new file mode 100644 index 00000000000..7c471764c6d --- /dev/null +++ b/extension/walkthrough/createProject.md @@ -0,0 +1,29 @@ +# Create your first Aspire app + +[Create a new Aspire project](command:aspire-vscode.new) to scaffold a new solution from a starter template. +The starter template gives you: +- An **apphost** that orchestrates your services, connections, and startup order +- A sample **API service** with health checks +- A **web frontend** that references the API + +**The apphost** is the heart of your app — it defines everything in code: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); +var apiService = builder.AddProject("apiservice") + .WithHttpHealthCheck("/health"); +builder.AddProject("webfrontend") + .WithExternalHttpEndpoints() + .WithReference(apiService) // web app can call the API + .WaitFor(apiService); // start API first +builder.Build().Run(); +``` + +| Method | What it does | +|---|---| +| `AddProject` | Registers a service | +| `WithReference` | Connects services | +| `WaitFor` | Controls startup order | +| `WithHttpHealthCheck` | Monitors health | + +Your application topology is defined in code, making it easy to understand, modify, and version control. [Learn more on aspire.dev](https://aspire.dev/get-started/first-app/) diff --git a/extension/walkthrough/dashboard.md b/extension/walkthrough/dashboard.md new file mode 100644 index 00000000000..910d92480d8 --- /dev/null +++ b/extension/walkthrough/dashboard.md @@ -0,0 +1,22 @@ +# The Aspire Dashboard + +The Aspire Dashboard gives you real-time visibility into your running application. It's also a lightweight [OpenTelemetry](https://opentelemetry.io/) viewer for any structured logs, metrics, or traces you have instrumented in your app. + +### What you'll see + +- **Resources** — all your services, containers, and executables with their current state +- **Endpoints** — live URLs for each service +- **Console Logs** — aggregated output from all services in one place +- **Structured Logs** — searchable, structured log entries with OpenTelemetry +- **Traces** — distributed traces showing request flow across services +- **Metrics** — performance counters and custom metrics + +### Health monitoring + +Each resource shows its health status at a glance: + +- 🟢 **Running** — service is healthy +- 🟡 **Starting** — service is spinning up +- 🔴 **Failed** — something went wrong + +The dashboard launches automatically when you run your app and is accessible from a local URL in your terminal output. diff --git a/extension/walkthrough/installCli.md b/extension/walkthrough/installCli.md new file mode 100644 index 00000000000..30f0d823909 --- /dev/null +++ b/extension/walkthrough/installCli.md @@ -0,0 +1,27 @@ +# Install the Aspire CLI + +The Aspire CLI is a cross-platform tool that helps you create, run, and manage Aspire applications. + +### Latest release + +> [Run install in terminal](command:aspire-vscode.installCliStable) + +| Platform | Command | +|----------|---------| +| macOS / Linux | `curl -sSL https://aspire.dev/install.sh \| bash` | +| Windows | `irm https://aspire.dev/install.ps1 \| iex` | + +### Daily build (preview) + +> [Run daily install in terminal](command:aspire-vscode.installCliDaily) + +| Platform | Command | +|----------|---------| +| macOS / Linux | `curl -sSL https://aspire.dev/install.sh \| bash -s -- -q dev` | +| Windows | `iex "& { $(irm https://aspire.dev/install.ps1) } -Quality dev"` | + +### Verify + +After installing, click **Verify installation** in the sidebar or run `aspire --version`. + +> For more details, see the [Aspire CLI installation guide](https://aspire.dev/get-started/install-cli/). diff --git a/extension/walkthrough/nextSteps.md b/extension/walkthrough/nextSteps.md new file mode 100644 index 00000000000..47148ed3d1a --- /dev/null +++ b/extension/walkthrough/nextSteps.md @@ -0,0 +1,28 @@ +# You're ready to build with Aspire! + +Here are some next steps to explore: + +### Add integrations + +Aspire has 40+ integrations for databases, message queues, cloud services, and more: + +- **Databases** — PostgreSQL, SQL Server, Redis, MongoDB, MySQL +- **Messaging** — RabbitMQ, Kafka, Azure Service Bus +- **Cloud** — Azure, AWS services +- **Containers** — any OCI-compatible container image + +Use the **Aspire: Add an integration** command to browse and add integrations to your project. + +### Deploy your app + +When you're ready to go to production, use the **Aspire: Publish deployment artifacts** command to generate deployment manifests for your app. + +For a full walkthrough, see [Deploy your first app](https://aspire.dev/get-started/deploy-first-app/) on aspire.dev. + +### Learn more + +- [Aspire documentation](https://aspire.dev/docs/) +- [Integration gallery](https://aspire.dev/integrations/gallery/) +- [Dashboard overview](https://aspire.dev/dashboard/overview/) +- [Deployment guide](https://aspire.dev/deployment/overview/) +- [Community & Discord](https://discord.com/invite/raNPcaaSj8) diff --git a/extension/walkthrough/runApp.md b/extension/walkthrough/runApp.md new file mode 100644 index 00000000000..ce1a8bdecfa --- /dev/null +++ b/extension/walkthrough/runApp.md @@ -0,0 +1,19 @@ +# Run your app + +Use the **Run apphost** or **Debug apphost** buttons in the sidebar, or run the commands from the Command Palette. You can also right-click an apphost in the Aspire view. + +When you run, the extension: +1. Discovers the apphost project in your workspace +2. Builds your solution +3. Launches all services in the correct order +4. Opens the **Aspire Dashboard** for real-time monitoring + +### Debugging +When you **debug** instead of run, the extension attaches debuggers to your services automatically — set breakpoints in any project and they'll be hit as requests flow through your app. + +### The dashboard +Once running, the dashboard shows all your resources, endpoints, logs, traces, and metrics in one place: + +![Aspire dashboard showing running resources](../resources/aspire-dashboard-dark.png) + +To learn more, see the [Aspire Dashboard overview](https://aspire.dev/dashboard/overview/). diff --git a/extension/walkthrough/welcome.md b/extension/walkthrough/welcome.md new file mode 100644 index 00000000000..616bddce908 --- /dev/null +++ b/extension/walkthrough/welcome.md @@ -0,0 +1,26 @@ +# Welcome to Aspire + +Aspire streamlines building, running, debugging, and deploying distributed apps. Define your services, databases, and frontends in code — then launch and debug everything with a single command. + +### Key benefits + +- **Unified development experience** — launch and debug your entire distributed application with a single command +- **Code-first configuration** — define your app's architecture in code, no complex config files required +- **Local orchestration** — automatically handle service startup, dependencies, and connections during development +- **Deployment flexibility** — deploy to Kubernetes, cloud providers, or your own servers using the same architecture definition +- **Extensible** — integrate with your favorite tools and services through a rich ecosystem of [integrations](https://aspire.dev/integrations/gallery/) + +### How it works + +1. Define your services and their connections in an **apphost** project +2. Run everything locally with a single command +3. Monitor it all through the **Aspire Dashboard** +4. Deploy the same architecture definition to production + +Aspire uses a code-first approach — your infrastructure definition lives alongside your code, with type safety, code completion, and version control built in. + +### Works with your stack + +Aspire is polyglot — it works with **C#**, **Python**, **JavaScript**, **TypeScript**, **Go**, **Java**, and more. + +[Learn more on aspire.dev](https://aspire.dev/docs/) diff --git a/playground/Stress/Stress.AppHost/Program.cs b/playground/Stress/Stress.AppHost/Program.cs index 001b0b673eb..f32a197eeec 100644 --- a/playground/Stress/Stress.AppHost/Program.cs +++ b/playground/Stress/Stress.AppHost/Program.cs @@ -112,7 +112,7 @@ displayName: "Stop all resources", executeCommand: async (c) => { - await ExecuteCommandForAllResourcesAsync(c.ServiceProvider, "resource-stop", c.CancellationToken); + await ExecuteCommandForAllResourcesAsync(c.ServiceProvider, KnownResourceCommands.StopCommand, c.CancellationToken); return CommandResults.Success(); }, commandOptions: new() { IconName = "Stop", IconVariant = IconVariant.Filled }) @@ -121,7 +121,7 @@ displayName: "Start all resources", executeCommand: async (c) => { - await ExecuteCommandForAllResourcesAsync(c.ServiceProvider, "resource-start", c.CancellationToken); + await ExecuteCommandForAllResourcesAsync(c.ServiceProvider, KnownResourceCommands.StartCommand, c.CancellationToken); return CommandResults.Success(); }, commandOptions: new() { IconName = "Play", IconVariant = IconVariant.Filled }); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..e8d1c41abd9 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.AppConfiguration": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..693f53d00c7 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +BBC4E06F9B0A1EED3C45E9F2D7F9252F4E5759D47A90F8507502F9A94CED3CFD \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..41222104634 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,6131 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to AzureAppConfigurationEmulatorResource */ +type AzureAppConfigurationEmulatorResourceHandle = Handle<'Aspire.Hosting.Azure.AppConfiguration/Aspire.Hosting.Azure.AzureAppConfigurationEmulatorResource'>; + +/** Handle to AzureAppConfigurationResource */ +type AzureAppConfigurationResourceHandle = Handle<'Aspire.Hosting.Azure.AppConfiguration/Aspire.Hosting.Azure.AzureAppConfigurationResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for AzureAppConfigurationRole */ +export enum AzureAppConfigurationRole { + AppConfigurationDataOwner = "AppConfigurationDataOwner", + AppConfigurationDataReader = "AppConfigurationDataReader", +} + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunAsEmulatorOptions { + configureEmulator?: (obj: AzureAppConfigurationEmulatorResource) => Promise; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + path?: string; +} + +export interface WithDataVolumeOptions { + name?: string; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHostPortOptions { + port?: number; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds an Azure App Configuration resource */ + /** @internal */ + async _addAzureAppConfigurationInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/addAzureAppConfiguration', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + addAzureAppConfiguration(name: string): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._addAzureAppConfigurationInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds an Azure App Configuration resource */ + addAzureAppConfiguration(name: string): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.addAzureAppConfiguration(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AzureAppConfigurationEmulatorResource +// ============================================================================ + +export class AzureAppConfigurationEmulatorResource extends ResourceBuilderBase { + constructor(handle: AzureAppConfigurationEmulatorResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AzureAppConfigurationEmulatorResourcePromise { + const isReadOnly = options?.isReadOnly; + return new AzureAppConfigurationEmulatorResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AzureAppConfigurationEmulatorResourcePromise { + const tag = options?.tag; + return new AzureAppConfigurationEmulatorResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AzureAppConfigurationEmulatorResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new AzureAppConfigurationEmulatorResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureAppConfigurationEmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AzureAppConfigurationEmulatorResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureAppConfigurationEmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureAppConfigurationEmulatorResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureAppConfigurationEmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureAppConfigurationEmulatorResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureAppConfigurationEmulatorResourcePromise { + const displayText = options?.displayText; + return new AzureAppConfigurationEmulatorResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureAppConfigurationEmulatorResourcePromise { + const displayText = options?.displayText; + return new AzureAppConfigurationEmulatorResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AzureAppConfigurationEmulatorResourcePromise { + const exitCode = options?.exitCode; + return new AzureAppConfigurationEmulatorResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureAppConfigurationEmulatorResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AzureAppConfigurationEmulatorResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureAppConfigurationEmulatorResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureAppConfigurationEmulatorResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AzureAppConfigurationEmulatorResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new AzureAppConfigurationEmulatorResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withDataBindMountInternal(path?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withDataBindMount', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a data bind mount for the App Configuration emulator */ + withDataBindMount(options?: WithDataBindMountOptions): AzureAppConfigurationEmulatorResourcePromise { + const path = options?.path; + return new AzureAppConfigurationEmulatorResourcePromise(this._withDataBindMountInternal(path)); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withDataVolume', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Adds a data volume for the App Configuration emulator */ + withDataVolume(options?: WithDataVolumeOptions): AzureAppConfigurationEmulatorResourcePromise { + const name = options?.name; + return new AzureAppConfigurationEmulatorResourcePromise(this._withDataVolumeInternal(name)); + } + + /** @internal */ + private async _withHostPortInternal(port?: number): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withHostPort', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Sets the host port for the App Configuration emulator */ + withHostPort(options?: WithHostPortOptions): AzureAppConfigurationEmulatorResourcePromise { + const port = options?.port; + return new AzureAppConfigurationEmulatorResourcePromise(this._withHostPortInternal(port)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withRoleAssignments', + rpcArgs + ); + return new AzureAppConfigurationEmulatorResource(result, this._client); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureAppConfigurationEmulatorResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureAppConfigurationEmulatorResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureAppConfigurationEmulatorResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds a data bind mount for the App Configuration emulator */ + withDataBindMount(options?: WithDataBindMountOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withDataBindMount(options))); + } + + /** Adds a data volume for the App Configuration emulator */ + withDataVolume(options?: WithDataVolumeOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Sets the host port for the App Configuration emulator */ + withHostPort(options?: WithHostPortOptions): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withHostPort(options))); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): AzureAppConfigurationEmulatorResourcePromise { + return new AzureAppConfigurationEmulatorResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// AzureAppConfigurationResource +// ============================================================================ + +export class AzureAppConfigurationResource extends ResourceBuilderBase { + constructor(handle: AzureAppConfigurationResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureAppConfigurationResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AzureAppConfigurationResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureAppConfigurationResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureAppConfigurationResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureAppConfigurationResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureAppConfigurationResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureAppConfigurationResourcePromise { + const displayText = options?.displayText; + return new AzureAppConfigurationResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureAppConfigurationResourcePromise { + const displayText = options?.displayText; + return new AzureAppConfigurationResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureAppConfigurationResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AzureAppConfigurationResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureAppConfigurationResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureAppConfigurationResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _runAsEmulatorInternal(configureEmulator?: (obj: AzureAppConfigurationEmulatorResource) => Promise): Promise { + const configureEmulatorId = configureEmulator ? registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as AzureAppConfigurationEmulatorResourceHandle; + const obj = new AzureAppConfigurationEmulatorResource(objHandle, this._client); + await configureEmulator(obj); + }) : undefined; + const rpcArgs: Record = { builder: this._handle }; + if (configureEmulator !== undefined) rpcArgs.configureEmulator = configureEmulatorId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/runAsEmulator', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Configures Azure App Configuration to run with the local emulator */ + runAsEmulator(options?: RunAsEmulatorOptions): AzureAppConfigurationResourcePromise { + const configureEmulator = options?.configureEmulator; + return new AzureAppConfigurationResourcePromise(this._runAsEmulatorInternal(configureEmulator)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withRoleAssignments', + rpcArgs + ); + return new AzureAppConfigurationResource(result, this._client); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureAppConfigurationResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureAppConfigurationResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureAppConfigurationResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Configures Azure App Configuration to run with the local emulator */ + runAsEmulator(options?: RunAsEmulatorOptions): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.runAsEmulator(options))); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): AzureAppConfigurationResourcePromise { + return new AzureAppConfigurationResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withRoleAssignments', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withRoleAssignments', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withRoleAssignments', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withRoleAssignments', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppConfiguration/withRoleAssignments', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ResourcePromise { + return new ResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns App Configuration roles to a resource */ + withRoleAssignments(target: AzureAppConfigurationResource, roles: AzureAppConfigurationRole[]): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.AppConfiguration/Aspire.Hosting.Azure.AzureAppConfigurationEmulatorResource', (handle, client) => new AzureAppConfigurationEmulatorResource(handle as AzureAppConfigurationEmulatorResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.AppConfiguration/Aspire.Hosting.Azure.AzureAppConfigurationResource', (handle, client) => new AzureAppConfigurationResource(handle as AzureAppConfigurationResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..86bbf67a878 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/apphost.ts @@ -0,0 +1,15 @@ +import { AzureAppConfigurationRole, createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const appConfig = await builder.addAzureAppConfiguration("appconfig"); +await appConfig.withRoleAssignments(appConfig, [AzureAppConfigurationRole.AppConfigurationDataOwner, AzureAppConfigurationRole.AppConfigurationDataReader]); +await appConfig.runAsEmulator({ + configureEmulator: async (emulator) => { + await emulator.withDataBindMount({ path: ".aace/appconfig" }); + await emulator.withDataVolume({ name: "appconfig-data" }); + await emulator.withHostPort({ port: 8483 }); + } +}); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppConfiguration/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..0f7ce3df537 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.ContainerRegistry": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..c364cbba82d --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +DBC64F54832647886AB4623206DC96C317F3F0AA5DAAE89507866008AA49F823 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..b6db30c1003 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5012 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to AzureContainerRegistryResource */ +type AzureContainerRegistryResourceHandle = Handle<'Aspire.Hosting.Azure.ContainerRegistry/Aspire.Hosting.Azure.AzureContainerRegistryResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithPurgeTaskOptions { + filter?: string; + ago?: number; + keep?: number; + taskName?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Exports AddAzureContainerRegistry for polyglot app hosts. */ + /** @internal */ + async _addAzureContainerRegistryInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.ContainerRegistry/addAzureContainerRegistry', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + addAzureContainerRegistry(name: string): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._addAzureContainerRegistryInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Exports AddAzureContainerRegistry for polyglot app hosts. */ + addAzureContainerRegistry(name: string): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.addAzureContainerRegistry(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AzureContainerRegistryResource +// ============================================================================ + +export class AzureContainerRegistryResource extends ResourceBuilderBase { + constructor(handle: AzureContainerRegistryResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureContainerRegistryResourcePromise { + const displayText = options?.displayText; + return new AzureContainerRegistryResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureContainerRegistryResourcePromise { + const displayText = options?.displayText; + return new AzureContainerRegistryResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureContainerRegistryResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureContainerRegistryResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withPurgeTaskInternal(schedule: string, filter?: string, ago?: number, keep?: number, taskName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, schedule }; + if (filter !== undefined) rpcArgs.filter = filter; + if (ago !== undefined) rpcArgs.ago = ago; + if (keep !== undefined) rpcArgs.keep = keep; + if (taskName !== undefined) rpcArgs.taskName = taskName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.ContainerRegistry/withPurgeTask', + rpcArgs + ); + return new AzureContainerRegistryResource(result, this._client); + } + + /** Exports WithPurgeTask for polyglot app hosts. */ + withPurgeTask(schedule: string, options?: WithPurgeTaskOptions): AzureContainerRegistryResourcePromise { + const filter = options?.filter; + const ago = options?.ago; + const keep = options?.keep; + const taskName = options?.taskName; + return new AzureContainerRegistryResourcePromise(this._withPurgeTaskInternal(schedule, filter, ago, keep, taskName)); + } + +} + +/** + * Thenable wrapper for AzureContainerRegistryResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureContainerRegistryResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureContainerRegistryResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Exports WithPurgeTask for polyglot app hosts. */ + withPurgeTask(schedule: string, options?: WithPurgeTaskOptions): AzureContainerRegistryResourcePromise { + return new AzureContainerRegistryResourcePromise(this._promise.then(obj => obj.withPurgeTask(schedule, options))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + const tag = options?.tag; + return new ContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.ContainerRegistry/Aspire.Hosting.Azure.AzureContainerRegistryResource', (handle, client) => new AzureContainerRegistryResource(handle as AzureContainerRegistryResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..efc2fc98010 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/apphost.ts @@ -0,0 +1,13 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +await builder.addAzureContainerRegistry("containerregistry") + .withPurgeTask("0 1 * * *", { + filter: "samples:*", + ago: 7, + keep: 5, + taskName: "purge-samples" + }); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.ContainerRegistry/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..5707c55c632 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.EventHubs": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..a2237b90dd6 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +32CD5EBFD8C6520E685BBC710C248F1BF6EB7FF87B6910BC1666577596FC393A \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..4d124ff473d --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,6761 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to AzureEventHubConsumerGroupResource */ +type AzureEventHubConsumerGroupResourceHandle = Handle<'Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubConsumerGroupResource'>; + +/** Handle to AzureEventHubResource */ +type AzureEventHubResourceHandle = Handle<'Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubResource'>; + +/** Handle to AzureEventHubsEmulatorResource */ +type AzureEventHubsEmulatorResourceHandle = Handle<'Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubsEmulatorResource'>; + +/** Handle to AzureEventHubsResource */ +type AzureEventHubsResourceHandle = Handle<'Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubsResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for AzureEventHubsRole */ +export enum AzureEventHubsRole { + AzureEventHubsDataOwner = "AzureEventHubsDataOwner", + AzureEventHubsDataReceiver = "AzureEventHubsDataReceiver", + AzureEventHubsDataSender = "AzureEventHubsDataSender", +} + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddConsumerGroupOptions { + groupName?: string; +} + +export interface AddHubOptions { + hubName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunAsEmulatorOptions { + configureContainer?: (obj: AzureEventHubsEmulatorResource) => Promise; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHostPortOptions { + port?: number; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds an Azure Event Hubs namespace resource */ + /** @internal */ + async _addAzureEventHubsInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/addAzureEventHubs', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + addAzureEventHubs(name: string): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._addAzureEventHubsInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds an Azure Event Hubs namespace resource */ + addAzureEventHubs(name: string): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.addAzureEventHubs(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AzureEventHubConsumerGroupResource +// ============================================================================ + +export class AzureEventHubConsumerGroupResource extends ResourceBuilderBase { + constructor(handle: AzureEventHubConsumerGroupResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubConsumerGroupResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubConsumerGroupResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubConsumerGroupResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubConsumerGroupResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubConsumerGroupResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureEventHubConsumerGroupResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureEventHubConsumerGroupResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureEventHubConsumerGroupResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureEventHubConsumerGroupResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// AzureEventHubResource +// ============================================================================ + +export class AzureEventHubResource extends ResourceBuilderBase { + constructor(handle: AzureEventHubResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** Gets the HubName property */ + hubName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.Azure/AzureEventHubResource.hubName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.Azure/AzureEventHubResource.setHubName', + { context: this._handle, value } + ); + } + }; + + /** Gets the PartitionCount property */ + partitionCount = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.Azure/AzureEventHubResource.partitionCount', + { context: this._handle } + ); + }, + set: async (value: number): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.Azure/AzureEventHubResource.setPartitionCount', + { context: this._handle, value } + ); + } + }; + + /** Gets the Name property */ + name = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.Azure/AzureEventHubResource.name', + { context: this._handle } + ); + }, + }; + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureEventHubResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withPropertiesInternal(configure: (obj: AzureEventHubResource) => Promise): Promise { + const configureId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as AzureEventHubResourceHandle; + const obj = new AzureEventHubResource(objHandle, this._client); + await configure(obj); + }); + const rpcArgs: Record = { builder: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withProperties', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Configures properties of an Azure Event Hub */ + withProperties(configure: (obj: AzureEventHubResource) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withPropertiesInternal(configure)); + } + + /** @internal */ + private async _addConsumerGroupInternal(name: string, groupName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (groupName !== undefined) rpcArgs.groupName = groupName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/addConsumerGroup', + rpcArgs + ); + return new AzureEventHubConsumerGroupResource(result, this._client); + } + + /** Adds an Azure Event Hub consumer group resource */ + addConsumerGroup(name: string, options?: AddConsumerGroupOptions): AzureEventHubConsumerGroupResourcePromise { + const groupName = options?.groupName; + return new AzureEventHubConsumerGroupResourcePromise(this._addConsumerGroupInternal(name, groupName)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureEventHubResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureEventHubResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureEventHubResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Configures properties of an Azure Event Hub */ + withProperties(configure: (obj: AzureEventHubResource) => Promise): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withProperties(configure))); + } + + /** Adds an Azure Event Hub consumer group resource */ + addConsumerGroup(name: string, options?: AddConsumerGroupOptions): AzureEventHubConsumerGroupResourcePromise { + return new AzureEventHubConsumerGroupResourcePromise(this._promise.then(obj => obj.addConsumerGroup(name, options))); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// AzureEventHubsEmulatorResource +// ============================================================================ + +export class AzureEventHubsEmulatorResource extends ResourceBuilderBase { + constructor(handle: AzureEventHubsEmulatorResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AzureEventHubsEmulatorResourcePromise { + const isReadOnly = options?.isReadOnly; + return new AzureEventHubsEmulatorResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AzureEventHubsEmulatorResourcePromise { + const tag = options?.tag; + return new AzureEventHubsEmulatorResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AzureEventHubsEmulatorResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new AzureEventHubsEmulatorResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureEventHubsEmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AzureEventHubsEmulatorResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureEventHubsEmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureEventHubsEmulatorResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureEventHubsEmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureEventHubsEmulatorResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubsEmulatorResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubsEmulatorResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubsEmulatorResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubsEmulatorResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AzureEventHubsEmulatorResourcePromise { + const exitCode = options?.exitCode; + return new AzureEventHubsEmulatorResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureEventHubsEmulatorResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AzureEventHubsEmulatorResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubsEmulatorResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureEventHubsEmulatorResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AzureEventHubsEmulatorResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new AzureEventHubsEmulatorResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withHostPortInternal(port?: number): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withHostPort', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the host port for the Event Hubs emulator endpoint */ + withHostPort(options?: WithHostPortOptions): AzureEventHubsEmulatorResourcePromise { + const port = options?.port; + return new AzureEventHubsEmulatorResourcePromise(this._withHostPortInternal(port)); + } + + /** @internal */ + private async _withConfigurationFileInternal(path: string): Promise { + const rpcArgs: Record = { builder: this._handle, path }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withConfigurationFile', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Sets the emulator configuration file path */ + withConfigurationFile(path: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withConfigurationFileInternal(path)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new AzureEventHubsEmulatorResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureEventHubsEmulatorResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureEventHubsEmulatorResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureEventHubsEmulatorResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Sets the host port for the Event Hubs emulator endpoint */ + withHostPort(options?: WithHostPortOptions): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withHostPort(options))); + } + + /** Sets the emulator configuration file path */ + withConfigurationFile(path: string): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withConfigurationFile(path))); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubsEmulatorResourcePromise { + return new AzureEventHubsEmulatorResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// AzureEventHubsResource +// ============================================================================ + +export class AzureEventHubsResource extends ResourceBuilderBase { + constructor(handle: AzureEventHubsResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureEventHubsResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AzureEventHubsResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureEventHubsResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureEventHubsResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureEventHubsResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureEventHubsResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubsResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubsResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubsResourcePromise { + const displayText = options?.displayText; + return new AzureEventHubsResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureEventHubsResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AzureEventHubsResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubsResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureEventHubsResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _addHubInternal(name: string, hubName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (hubName !== undefined) rpcArgs.hubName = hubName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/addHub', + rpcArgs + ); + return new AzureEventHubResource(result, this._client); + } + + /** Adds an Azure Event Hub resource */ + addHub(name: string, options?: AddHubOptions): AzureEventHubResourcePromise { + const hubName = options?.hubName; + return new AzureEventHubResourcePromise(this._addHubInternal(name, hubName)); + } + + /** @internal */ + private async _runAsEmulatorInternal(configureContainer?: (obj: AzureEventHubsEmulatorResource) => Promise): Promise { + const configureContainerId = configureContainer ? registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as AzureEventHubsEmulatorResourceHandle; + const obj = new AzureEventHubsEmulatorResource(objHandle, this._client); + await configureContainer(obj); + }) : undefined; + const rpcArgs: Record = { builder: this._handle }; + if (configureContainer !== undefined) rpcArgs.configureContainer = configureContainerId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/runAsEmulator', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Configures the Azure Event Hubs resource to run with the local emulator */ + runAsEmulator(options?: RunAsEmulatorOptions): AzureEventHubsResourcePromise { + const configureContainer = options?.configureContainer; + return new AzureEventHubsResourcePromise(this._runAsEmulatorInternal(configureContainer)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new AzureEventHubsResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureEventHubsResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureEventHubsResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureEventHubsResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds an Azure Event Hub resource */ + addHub(name: string, options?: AddHubOptions): AzureEventHubResourcePromise { + return new AzureEventHubResourcePromise(this._promise.then(obj => obj.addHub(name, options))); + } + + /** Configures the Azure Event Hubs resource to run with the local emulator */ + runAsEmulator(options?: RunAsEmulatorOptions): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.runAsEmulator(options))); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): AzureEventHubsResourcePromise { + return new AzureEventHubsResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.EventHubs/withRoleAssignments', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ResourcePromise { + return new ResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Event Hubs roles to a resource */ + withRoleAssignments(target: AzureEventHubsResource, roles: AzureEventHubsRole[]): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubConsumerGroupResource', (handle, client) => new AzureEventHubConsumerGroupResource(handle as AzureEventHubConsumerGroupResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubResource', (handle, client) => new AzureEventHubResource(handle as AzureEventHubResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubsEmulatorResource', (handle, client) => new AzureEventHubsEmulatorResource(handle as AzureEventHubsEmulatorResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.AzureEventHubsResource', (handle, client) => new AzureEventHubsResource(handle as AzureEventHubsResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..83bbb811f54 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/apphost.ts @@ -0,0 +1,29 @@ +import { AzureEventHubsRole, createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); +const eventHubs = await builder.addAzureEventHubs('eventhubs'); + +await eventHubs.withRoleAssignments(eventHubs, [AzureEventHubsRole.AzureEventHubsDataOwner]); + +const hub = await eventHubs.addHub('orders', { hubName: 'orders-hub' }); +await hub.withProperties(async (configuredHub) => { + await configuredHub.hubName.set('orders-hub'); + const _hubName: string = await configuredHub.hubName.get(); + + await configuredHub.partitionCount.set(2); + const _partitionCount: number | undefined = await configuredHub.partitionCount.get(); +}); + +const consumerGroup = await hub.addConsumerGroup('processors', { groupName: 'processor-group' }); +await consumerGroup.withRoleAssignments(eventHubs, [AzureEventHubsRole.AzureEventHubsDataReceiver]); + +await eventHubs.runAsEmulator({ + configureContainer: async (emulator) => { + await emulator + .withHostPort({ port: 5673 }) + .withConfigurationFile('./eventhubs.config.json') + .withRoleAssignments(eventHubs, [AzureEventHubsRole.AzureEventHubsDataSender]); + } +}); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.EventHubs/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..d292b9e3fd3 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,8 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.Redis": "", + "Aspire.Hosting.Azure.KeyVault": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..3875aedfe7c --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +421C194505615774A34906AC3585B5CEBB899A8D33D3CAE9C80394DD07C85E12 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..7acd47f2a08 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,6766 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to AzureKeyVaultResource */ +type AzureKeyVaultResourceHandle = Handle<'Aspire.Hosting.Azure.KeyVault/Aspire.Hosting.Azure.AzureKeyVaultResource'>; + +/** Handle to AzureKeyVaultSecretResource */ +type AzureKeyVaultSecretResourceHandle = Handle<'Aspire.Hosting.Azure.KeyVault/Aspire.Hosting.Azure.AzureKeyVaultSecretResource'>; + +/** Handle to AzureManagedRedisResource */ +type AzureManagedRedisResourceHandle = Handle<'Aspire.Hosting.Azure.Redis/Aspire.Hosting.Azure.AzureManagedRedisResource'>; + +/** Handle to IAzureKeyVaultResource */ +type IAzureKeyVaultResourceHandle = Handle<'Aspire.Hosting.Azure/Aspire.Hosting.Azure.IAzureKeyVaultResource'>; + +/** Handle to IAzureKeyVaultSecretReference */ +type IAzureKeyVaultSecretReferenceHandle = Handle<'Aspire.Hosting.Azure/Aspire.Hosting.Azure.IAzureKeyVaultSecretReference'>; + +/** Handle to RedisResource */ +type RedisResourceHandle = Handle<'Aspire.Hosting.Redis/Aspire.Hosting.ApplicationModel.RedisResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for AzureKeyVaultRole */ +export enum AzureKeyVaultRole { + KeyVaultAdministrator = "KeyVaultAdministrator", + KeyVaultCertificateUser = "KeyVaultCertificateUser", + KeyVaultCertificatesOfficer = "KeyVaultCertificatesOfficer", + KeyVaultContributor = "KeyVaultContributor", + KeyVaultCryptoOfficer = "KeyVaultCryptoOfficer", + KeyVaultCryptoServiceEncryptionUser = "KeyVaultCryptoServiceEncryptionUser", + KeyVaultCryptoServiceReleaseUser = "KeyVaultCryptoServiceReleaseUser", + KeyVaultCryptoUser = "KeyVaultCryptoUser", + KeyVaultDataAccessAdministrator = "KeyVaultDataAccessAdministrator", + KeyVaultReader = "KeyVaultReader", + KeyVaultSecretsOfficer = "KeyVaultSecretsOfficer", + KeyVaultSecretsUser = "KeyVaultSecretsUser", + ManagedHsmContributor = "ManagedHsmContributor", +} + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunAsContainerOptions { + configureContainer?: (obj: RedisResource) => Promise; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds an Azure Managed Redis resource */ + /** @internal */ + async _addAzureManagedRedisInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Redis/addAzureManagedRedis', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + addAzureManagedRedis(name: string): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._addAzureManagedRedisInternal(name)); + } + + /** Adds an Azure Key Vault resource */ + /** @internal */ + async _addAzureKeyVaultInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/addAzureKeyVault', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + addAzureKeyVault(name: string): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._addAzureKeyVaultInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds an Azure Managed Redis resource */ + addAzureManagedRedis(name: string): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.addAzureManagedRedis(name))); + } + + /** Adds an Azure Key Vault resource */ + addAzureKeyVault(name: string): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.addAzureKeyVault(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AzureKeyVaultResource +// ============================================================================ + +export class AzureKeyVaultResource extends ResourceBuilderBase { + constructor(handle: AzureKeyVaultResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureKeyVaultResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AzureKeyVaultResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureKeyVaultResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureKeyVaultResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureKeyVaultResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureKeyVaultResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureKeyVaultResourcePromise { + const displayText = options?.displayText; + return new AzureKeyVaultResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureKeyVaultResourcePromise { + const displayText = options?.displayText; + return new AzureKeyVaultResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureKeyVaultResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AzureKeyVaultResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureKeyVaultResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureKeyVaultResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new AzureKeyVaultResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + + /** Gets a secret reference from the Azure Key Vault */ + async getSecret(secretName: string): Promise { + const rpcArgs: Record = { builder: this._handle, secretName }; + return await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/getSecret', + rpcArgs + ); + } + + /** @internal */ + private async _addSecretInternal(name: string, parameterResource: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name, parameterResource }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/addSecret', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds a secret to the Azure Key Vault from a parameter resource */ + addSecret(name: string, parameterResource: ParameterResource): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._addSecretInternal(name, parameterResource)); + } + + /** @internal */ + private async _addSecretFromExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/addSecretFromExpression', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds a secret to the Azure Key Vault from a reference expression */ + addSecretFromExpression(name: string, value: ReferenceExpression): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._addSecretFromExpressionInternal(name, value)); + } + + /** @internal */ + private async _addSecretWithNameInternal(name: string, secretName: string, parameterResource: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name, secretName, parameterResource }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/addSecretWithName', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds a named secret to the Azure Key Vault from a parameter resource */ + addSecretWithName(name: string, secretName: string, parameterResource: ParameterResource): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._addSecretWithNameInternal(name, secretName, parameterResource)); + } + + /** @internal */ + private async _addSecretWithNameFromExpressionInternal(name: string, secretName: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, secretName, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/addSecretWithNameFromExpression', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds a named secret to the Azure Key Vault from a reference expression */ + addSecretWithNameFromExpression(name: string, secretName: string, value: ReferenceExpression): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._addSecretWithNameFromExpressionInternal(name, secretName, value)); + } + +} + +/** + * Thenable wrapper for AzureKeyVaultResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureKeyVaultResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureKeyVaultResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): AzureKeyVaultResourcePromise { + return new AzureKeyVaultResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + + /** Gets a secret reference from the Azure Key Vault */ + getSecret(secretName: string): Promise { + return this._promise.then(obj => obj.getSecret(secretName)); + } + + /** Adds a secret to the Azure Key Vault from a parameter resource */ + addSecret(name: string, parameterResource: ParameterResource): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.addSecret(name, parameterResource))); + } + + /** Adds a secret to the Azure Key Vault from a reference expression */ + addSecretFromExpression(name: string, value: ReferenceExpression): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.addSecretFromExpression(name, value))); + } + + /** Adds a named secret to the Azure Key Vault from a parameter resource */ + addSecretWithName(name: string, secretName: string, parameterResource: ParameterResource): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.addSecretWithName(name, secretName, parameterResource))); + } + + /** Adds a named secret to the Azure Key Vault from a reference expression */ + addSecretWithNameFromExpression(name: string, secretName: string, value: ReferenceExpression): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.addSecretWithNameFromExpression(name, secretName, value))); + } + +} + +// ============================================================================ +// AzureKeyVaultSecretResource +// ============================================================================ + +export class AzureKeyVaultSecretResource extends ResourceBuilderBase { + constructor(handle: AzureKeyVaultSecretResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureKeyVaultSecretResourcePromise { + const displayText = options?.displayText; + return new AzureKeyVaultSecretResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureKeyVaultSecretResourcePromise { + const displayText = options?.displayText; + return new AzureKeyVaultSecretResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureKeyVaultSecretResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureKeyVaultSecretResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new AzureKeyVaultSecretResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureKeyVaultSecretResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureKeyVaultSecretResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureKeyVaultSecretResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): AzureKeyVaultSecretResourcePromise { + return new AzureKeyVaultSecretResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// AzureManagedRedisResource +// ============================================================================ + +export class AzureManagedRedisResource extends ResourceBuilderBase { + constructor(handle: AzureManagedRedisResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureManagedRedisResourcePromise { + const displayText = options?.displayText; + return new AzureManagedRedisResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureManagedRedisResourcePromise { + const displayText = options?.displayText; + return new AzureManagedRedisResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureManagedRedisResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureManagedRedisResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _runAsContainerInternal(configureContainer?: (obj: RedisResource) => Promise): Promise { + const configureContainerId = configureContainer ? registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as RedisResourceHandle; + const obj = new RedisResource(objHandle, this._client); + await configureContainer(obj); + }) : undefined; + const rpcArgs: Record = { builder: this._handle }; + if (configureContainer !== undefined) rpcArgs.configureContainer = configureContainerId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Redis/runAsContainer', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Configures Azure Managed Redis to run in a local container */ + runAsContainer(options?: RunAsContainerOptions): AzureManagedRedisResourcePromise { + const configureContainer = options?.configureContainer; + return new AzureManagedRedisResourcePromise(this._runAsContainerInternal(configureContainer)); + } + + /** @internal */ + private async _withAccessKeyAuthenticationInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Redis/withAccessKeyAuthentication', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Configures Azure Managed Redis to use access key authentication */ + withAccessKeyAuthentication(): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withAccessKeyAuthenticationInternal()); + } + + /** @internal */ + private async _withAccessKeyAuthenticationWithKeyVaultInternal(keyVaultBuilder: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, keyVaultBuilder }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Redis/withAccessKeyAuthenticationWithKeyVault', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Configures Azure Managed Redis to use access key authentication with a specific Key Vault */ + withAccessKeyAuthenticationWithKeyVault(keyVaultBuilder: ResourceBuilderBase): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withAccessKeyAuthenticationWithKeyVaultInternal(keyVaultBuilder)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new AzureManagedRedisResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureManagedRedisResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureManagedRedisResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureManagedRedisResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Configures Azure Managed Redis to run in a local container */ + runAsContainer(options?: RunAsContainerOptions): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.runAsContainer(options))); + } + + /** Configures Azure Managed Redis to use access key authentication */ + withAccessKeyAuthentication(): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withAccessKeyAuthentication())); + } + + /** Configures Azure Managed Redis to use access key authentication with a specific Key Vault */ + withAccessKeyAuthenticationWithKeyVault(keyVaultBuilder: ResourceBuilderBase): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withAccessKeyAuthenticationWithKeyVault(keyVaultBuilder))); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): AzureManagedRedisResourcePromise { + return new AzureManagedRedisResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// RedisResource +// ============================================================================ + +export class RedisResource extends ResourceBuilderBase { + constructor(handle: RedisResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): RedisResourcePromise { + const isReadOnly = options?.isReadOnly; + return new RedisResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): RedisResourcePromise { + return new RedisResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): RedisResourcePromise { + return new RedisResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): RedisResourcePromise { + return new RedisResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): RedisResourcePromise { + const tag = options?.tag; + return new RedisResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): RedisResourcePromise { + return new RedisResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): RedisResourcePromise { + return new RedisResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): RedisResourcePromise { + return new RedisResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): RedisResourcePromise { + return new RedisResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): RedisResourcePromise { + return new RedisResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): RedisResourcePromise { + return new RedisResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): RedisResourcePromise { + return new RedisResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): RedisResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new RedisResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): RedisResourcePromise { + return new RedisResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): RedisResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new RedisResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): RedisResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new RedisResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): RedisResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new RedisResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): RedisResourcePromise { + return new RedisResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): RedisResourcePromise { + return new RedisResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): RedisResourcePromise { + const displayText = options?.displayText; + return new RedisResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): RedisResourcePromise { + const displayText = options?.displayText; + return new RedisResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): RedisResourcePromise { + return new RedisResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): RedisResourcePromise { + return new RedisResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): RedisResourcePromise { + const exitCode = options?.exitCode; + return new RedisResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): RedisResourcePromise { + return new RedisResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): RedisResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new RedisResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): RedisResourcePromise { + const commandOptions = options?.commandOptions; + return new RedisResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): RedisResourcePromise { + return new RedisResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): RedisResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new RedisResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new RedisResource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): RedisResourcePromise { + return new RedisResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for RedisResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class RedisResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: RedisResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): RedisResourcePromise { + return new RedisResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.KeyVault/withRoleAssignments', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ResourcePromise { + return new ResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Key Vault roles to a resource */ + withRoleAssignments(target: AzureKeyVaultResource, roles: AzureKeyVaultRole[]): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.KeyVault/Aspire.Hosting.Azure.AzureKeyVaultResource', (handle, client) => new AzureKeyVaultResource(handle as AzureKeyVaultResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.KeyVault/Aspire.Hosting.Azure.AzureKeyVaultSecretResource', (handle, client) => new AzureKeyVaultSecretResource(handle as AzureKeyVaultSecretResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.Redis/Aspire.Hosting.Azure.AzureManagedRedisResource', (handle, client) => new AzureManagedRedisResource(handle as AzureManagedRedisResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Redis/Aspire.Hosting.ApplicationModel.RedisResource', (handle, client) => new RedisResource(handle as RedisResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..46e8b4654be --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/apphost.ts @@ -0,0 +1,16 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const keyVault = await builder.addAzureKeyVault("vault"); +const cache = await builder.addAzureManagedRedis("cache"); + +await cache.withAccessKeyAuthentication(); +await cache.withAccessKeyAuthenticationWithKeyVault(keyVault); +await cache.runAsContainer({ + configureContainer: async (container) => { + await container.withVolume("/data"); + } +}); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..00f6d3b5743 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Redis/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts", ".modules/**/*.d.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..fd0aad5ed98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.Search": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..928c69770dd --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +D052B842D8DE3E3B7D8FB14DF049572615640B38B9A1436C7433AFAD9081FF7B \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..3d8dcd1ea09 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5104 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to AzureSearchResource */ +type AzureSearchResourceHandle = Handle<'Aspire.Hosting.Azure.Search/Aspire.Hosting.Azure.AzureSearchResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for AzureSearchRole */ +export enum AzureSearchRole { + SearchIndexDataContributor = "SearchIndexDataContributor", + SearchIndexDataReader = "SearchIndexDataReader", + SearchServiceContributor = "SearchServiceContributor", +} + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds an Azure AI Search service resource */ + /** @internal */ + async _addAzureSearchInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Search/addAzureSearch', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + addAzureSearch(name: string): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._addAzureSearchInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds an Azure AI Search service resource */ + addAzureSearch(name: string): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.addAzureSearch(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AzureSearchResource +// ============================================================================ + +export class AzureSearchResource extends ResourceBuilderBase { + constructor(handle: AzureSearchResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureSearchResourcePromise { + const displayText = options?.displayText; + return new AzureSearchResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureSearchResourcePromise { + const displayText = options?.displayText; + return new AzureSearchResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureSearchResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureSearchResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureSearchResource, roles: AzureSearchRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Search/withRoleAssignments', + rpcArgs + ); + return new AzureSearchResource(result, this._client); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureSearchResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureSearchResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureSearchResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): AzureSearchResourcePromise { + return new AzureSearchResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + const tag = options?.tag; + return new ContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureSearchResource, roles: AzureSearchRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Search/withRoleAssignments', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureSearchResource, roles: AzureSearchRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Search/withRoleAssignments', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureSearchResource, roles: AzureSearchRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Search/withRoleAssignments', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureSearchResource, roles: AzureSearchRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Search/withRoleAssignments', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureSearchResource, roles: AzureSearchRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.Search/withRoleAssignments', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ResourcePromise { + return new ResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure AI Search roles to a resource */ + withRoleAssignments(target: AzureSearchResource, roles: AzureSearchRole[]): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.Search/Aspire.Hosting.Azure.AzureSearchResource', (handle, client) => new AzureSearchResource(handle as AzureSearchResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..add21c77bf8 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/apphost.ts @@ -0,0 +1,11 @@ +import { AzureSearchRole, createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); +const search = await builder.addAzureSearch('search'); + +await search.withRoleAssignments(search, [ + AzureSearchRole.SearchServiceContributor, + AzureSearchRole.SearchIndexDataReader +]); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.Search/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..e06b3437f54 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.SignalR": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..84c728aae1c --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +A0FC5C221339ED77FC8317C4B1C9900918CF092D44BACDE39AA4FD68D1A8F0B9 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..102000535ac --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5907 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to AzureSignalRResource */ +type AzureSignalRResourceHandle = Handle<'Aspire.Hosting.Azure.SignalR/Aspire.Hosting.ApplicationModel.AzureSignalRResource'>; + +/** Handle to AzureSignalREmulatorResource */ +type AzureSignalREmulatorResourceHandle = Handle<'Aspire.Hosting.Azure.SignalR/Aspire.Hosting.Azure.AzureSignalREmulatorResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunAsEmulatorOptions { + configureContainer?: (obj: AzureSignalREmulatorResource) => Promise; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds an Azure SignalR resource to the application model. */ + /** @internal */ + async _addAzureSignalRInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.SignalR/addAzureSignalR', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + addAzureSignalR(name: string): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._addAzureSignalRInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds an Azure SignalR resource to the application model. */ + addAzureSignalR(name: string): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.addAzureSignalR(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AzureSignalREmulatorResource +// ============================================================================ + +export class AzureSignalREmulatorResource extends ResourceBuilderBase { + constructor(handle: AzureSignalREmulatorResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AzureSignalREmulatorResourcePromise { + const isReadOnly = options?.isReadOnly; + return new AzureSignalREmulatorResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AzureSignalREmulatorResourcePromise { + const tag = options?.tag; + return new AzureSignalREmulatorResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AzureSignalREmulatorResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new AzureSignalREmulatorResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureSignalREmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AzureSignalREmulatorResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureSignalREmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureSignalREmulatorResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureSignalREmulatorResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureSignalREmulatorResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureSignalREmulatorResourcePromise { + const displayText = options?.displayText; + return new AzureSignalREmulatorResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureSignalREmulatorResourcePromise { + const displayText = options?.displayText; + return new AzureSignalREmulatorResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AzureSignalREmulatorResourcePromise { + const exitCode = options?.exitCode; + return new AzureSignalREmulatorResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureSignalREmulatorResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AzureSignalREmulatorResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureSignalREmulatorResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureSignalREmulatorResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new AzureSignalREmulatorResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AzureSignalREmulatorResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new AzureSignalREmulatorResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for AzureSignalREmulatorResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureSignalREmulatorResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureSignalREmulatorResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AzureSignalREmulatorResourcePromise { + return new AzureSignalREmulatorResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// AzureSignalRResource +// ============================================================================ + +export class AzureSignalRResource extends ResourceBuilderBase { + constructor(handle: AzureSignalRResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureSignalRResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AzureSignalRResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureSignalRResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureSignalRResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureSignalRResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AzureSignalRResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureSignalRResourcePromise { + const displayText = options?.displayText; + return new AzureSignalRResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureSignalRResourcePromise { + const displayText = options?.displayText; + return new AzureSignalRResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureSignalRResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AzureSignalRResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureSignalRResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureSignalRResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _runAsEmulatorInternal(configureContainer?: (obj: AzureSignalREmulatorResource) => Promise): Promise { + const configureContainerId = configureContainer ? registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as AzureSignalREmulatorResourceHandle; + const obj = new AzureSignalREmulatorResource(objHandle, this._client); + await configureContainer(obj); + }) : undefined; + const rpcArgs: Record = { builder: this._handle }; + if (configureContainer !== undefined) rpcArgs.configureContainer = configureContainerId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.SignalR/runAsEmulator', + rpcArgs + ); + return new AzureSignalRResource(result, this._client); + } + + /** Exports RunAsEmulator for polyglot app hosts. */ + runAsEmulator(options?: RunAsEmulatorOptions): AzureSignalRResourcePromise { + const configureContainer = options?.configureContainer; + return new AzureSignalRResourcePromise(this._runAsEmulatorInternal(configureContainer)); + } + +} + +/** + * Thenable wrapper for AzureSignalRResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureSignalRResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureSignalRResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Exports RunAsEmulator for polyglot app hosts. */ + runAsEmulator(options?: RunAsEmulatorOptions): AzureSignalRResourcePromise { + return new AzureSignalRResourcePromise(this._promise.then(obj => obj.runAsEmulator(options))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.SignalR/Aspire.Hosting.Azure.AzureSignalREmulatorResource', (handle, client) => new AzureSignalREmulatorResource(handle as AzureSignalREmulatorResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.SignalR/Aspire.Hosting.ApplicationModel.AzureSignalRResource', (handle, client) => new AzureSignalRResource(handle as AzureSignalRResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..79a88d44c4f --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/apphost.ts @@ -0,0 +1,6 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); +const signalr = await builder.addAzureSignalR('signalr'); +await signalr.runAsEmulator(); +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.SignalR/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..8fca5845308 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.WebPubSub": "" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..e461a07a860 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +2E6B733AC69A0F4B4766C0E528F658EBDFB5D251C2836486B2B217CBD0AB6C3C \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..ecec669a5b7 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5430 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to AzureWebPubSubHubResource */ +type AzureWebPubSubHubResourceHandle = Handle<'Aspire.Hosting.Azure.WebPubSub/Aspire.Hosting.ApplicationModel.AzureWebPubSubHubResource'>; + +/** Handle to AzureWebPubSubResource */ +type AzureWebPubSubResourceHandle = Handle<'Aspire.Hosting.Azure.WebPubSub/Aspire.Hosting.ApplicationModel.AzureWebPubSubResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for AzureWebPubSubRole */ +export enum AzureWebPubSubRole { + WebPubSubContributor = "WebPubSubContributor", + WebPubSubServiceOwner = "WebPubSubServiceOwner", + WebPubSubServiceReader = "WebPubSubServiceReader", +} + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddEventHandlerOptions { + userEventPattern?: string; + systemEvents?: string[]; +} + +export interface AddHubOptions { + hubName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds an Azure Web PubSub resource to the distributed application model. */ + /** @internal */ + async _addAzureWebPubSubInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/addAzureWebPubSub', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + addAzureWebPubSub(name: string): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._addAzureWebPubSubInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds an Azure Web PubSub resource to the distributed application model. */ + addAzureWebPubSub(name: string): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.addAzureWebPubSub(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AzureWebPubSubHubResource +// ============================================================================ + +export class AzureWebPubSubHubResource extends ResourceBuilderBase { + constructor(handle: AzureWebPubSubHubResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureWebPubSubHubResourcePromise { + const displayText = options?.displayText; + return new AzureWebPubSubHubResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureWebPubSubHubResourcePromise { + const displayText = options?.displayText; + return new AzureWebPubSubHubResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureWebPubSubHubResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureWebPubSubHubResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _addEventHandlerInternal(urlExpression: ReferenceExpression, userEventPattern?: string, systemEvents?: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, urlExpression }; + if (userEventPattern !== undefined) rpcArgs.userEventPattern = userEventPattern; + if (systemEvents !== undefined) rpcArgs.systemEvents = systemEvents; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/addEventHandler2', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Adds an event handler to an Azure Web PubSub hub. */ + addEventHandler(urlExpression: ReferenceExpression, options?: AddEventHandlerOptions): AzureWebPubSubHubResourcePromise { + const userEventPattern = options?.userEventPattern; + const systemEvents = options?.systemEvents; + return new AzureWebPubSubHubResourcePromise(this._addEventHandlerInternal(urlExpression, userEventPattern, systemEvents)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/withRoleAssignments', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureWebPubSubHubResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureWebPubSubHubResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureWebPubSubHubResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds an event handler to an Azure Web PubSub hub. */ + addEventHandler(urlExpression: ReferenceExpression, options?: AddEventHandlerOptions): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.addEventHandler(urlExpression, options))); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// AzureWebPubSubResource +// ============================================================================ + +export class AzureWebPubSubResource extends ResourceBuilderBase { + constructor(handle: AzureWebPubSubResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureWebPubSubResourcePromise { + const displayText = options?.displayText; + return new AzureWebPubSubResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureWebPubSubResourcePromise { + const displayText = options?.displayText; + return new AzureWebPubSubResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureWebPubSubResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureWebPubSubResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _addHubInternal(name: string, hubName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (hubName !== undefined) rpcArgs.hubName = hubName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/addHub', + rpcArgs + ); + return new AzureWebPubSubHubResource(result, this._client); + } + + /** Adds a hub to the Azure Web PubSub resource. */ + addHub(name: string, options?: AddHubOptions): AzureWebPubSubHubResourcePromise { + const hubName = options?.hubName; + return new AzureWebPubSubHubResourcePromise(this._addHubInternal(name, hubName)); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/withRoleAssignments', + rpcArgs + ); + return new AzureWebPubSubResource(result, this._client); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for AzureWebPubSubResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureWebPubSubResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureWebPubSubResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds a hub to the Azure Web PubSub resource. */ + addHub(name: string, options?: AddHubOptions): AzureWebPubSubHubResourcePromise { + return new AzureWebPubSubHubResourcePromise(this._promise.then(obj => obj.addHub(name, options))); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): AzureWebPubSubResourcePromise { + return new AzureWebPubSubResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + const tag = options?.tag; + return new ContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/withRoleAssignments', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/withRoleAssignments', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/withRoleAssignments', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/withRoleAssignments', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withRoleAssignmentsInternal(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): Promise { + const rpcArgs: Record = { builder: this._handle, target, roles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.WebPubSub/withRoleAssignments', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ResourcePromise { + return new ResourcePromise(this._withRoleAssignmentsInternal(target, roles)); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Assigns Azure Web PubSub roles to a resource */ + withRoleAssignments(target: AzureWebPubSubResource, roles: AzureWebPubSubRole[]): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withRoleAssignments(target, roles))); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.WebPubSub/Aspire.Hosting.ApplicationModel.AzureWebPubSubHubResource', (handle, client) => new AzureWebPubSubHubResource(handle as AzureWebPubSubHubResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.WebPubSub/Aspire.Hosting.ApplicationModel.AzureWebPubSubResource', (handle, client) => new AzureWebPubSubResource(handle as AzureWebPubSubResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..639c50026cc --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/apphost.ts @@ -0,0 +1,35 @@ +import { createBuilder, AzureWebPubSubRole } from './.modules/aspire.js'; +import { refExpr } from './.modules/base.js'; + +const builder = await createBuilder(); + +// addAzureWebPubSub — factory method +const webpubsub = await builder.addAzureWebPubSub("webpubsub"); + +// addHub — adds a hub to the Web PubSub resource (with optional hubName) +const hub = await webpubsub.addHub("myhub"); +const hubWithName = await webpubsub.addHub("hub2", { hubName: "customhub" }); + +// addEventHandler — adds an event handler to a hub +await hub.addEventHandler(refExpr`https://example.com/handler`); +await hub.addEventHandler(refExpr`https://example.com/handler2`, { + userEventPattern: "event1", + systemEvents: ["connect", "connected"], +}); + +// withRoleAssignments — assigns roles on a container resource +const container = await builder.addContainer("mycontainer", "mcr.microsoft.com/dotnet/samples:aspnetapp"); +await container.withRoleAssignments(webpubsub, [ + AzureWebPubSubRole.WebPubSubServiceOwner, + AzureWebPubSubRole.WebPubSubServiceReader, + AzureWebPubSubRole.WebPubSubContributor, +]); + +// withRoleAssignments — also available directly on AzureWebPubSubResource builder +await webpubsub.withRoleAssignments(webpubsub, [AzureWebPubSubRole.WebPubSubServiceReader]); + +// withReference — generic, works via IResourceWithConnectionString +await container.withReference(webpubsub); +await container.withReference(hub); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..00f6d3b5743 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.WebPubSub/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts", ".modules/**/*.d.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..583e157d39c --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.DevTunnels": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..38c30f4f3ca --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +86023D404399D568298B0CBF9086DA716B40E9C86EBC3F3410AF485AF2AB8350 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..6b484b278d6 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5524 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to DevTunnelResource */ +type DevTunnelResourceHandle = Handle<'Aspire.Hosting.DevTunnels/Aspire.Hosting.DevTunnels.DevTunnelResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddDevTunnelOptions { + tunnelId?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a Dev Tunnel resource to the distributed application model. */ + /** @internal */ + async _addDevTunnelInternal(name: string, tunnelId?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (tunnelId !== undefined) rpcArgs.tunnelId = tunnelId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.DevTunnels/addDevTunnel', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + addDevTunnel(name: string, options?: AddDevTunnelOptions): DevTunnelResourcePromise { + const tunnelId = options?.tunnelId; + return new DevTunnelResourcePromise(this._addDevTunnelInternal(name, tunnelId)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a Dev Tunnel resource to the distributed application model. */ + addDevTunnel(name: string, options?: AddDevTunnelOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.addDevTunnel(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + const tag = options?.tag; + return new ContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// DevTunnelResource +// ============================================================================ + +export class DevTunnelResource extends ResourceBuilderBase { + constructor(handle: DevTunnelResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): DevTunnelResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new DevTunnelResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): DevTunnelResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new DevTunnelResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): DevTunnelResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new DevTunnelResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): DevTunnelResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new DevTunnelResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): DevTunnelResourcePromise { + const displayText = options?.displayText; + return new DevTunnelResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): DevTunnelResourcePromise { + const displayText = options?.displayText; + return new DevTunnelResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): DevTunnelResourcePromise { + const exitCode = options?.exitCode; + return new DevTunnelResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): DevTunnelResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new DevTunnelResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): DevTunnelResourcePromise { + const commandOptions = options?.commandOptions; + return new DevTunnelResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withTunnelReferenceAllInternal(resourceBuilder: ResourceBuilderBase, allowAnonymous: boolean): Promise { + const rpcArgs: Record = { tunnelBuilder: this._handle, resourceBuilder, allowAnonymous }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.DevTunnels/withReferenceResourceAnonymous', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Configures the dev tunnel to expose all endpoints on the referenced resource. */ + withTunnelReferenceAll(resourceBuilder: ResourceBuilderBase, allowAnonymous: boolean): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withTunnelReferenceAllInternal(resourceBuilder, allowAnonymous)); + } + + /** @internal */ + private async _withTunnelReferenceInternal(targetEndpoint: EndpointReference): Promise { + const rpcArgs: Record = { tunnelBuilder: this._handle, targetEndpoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.DevTunnels/withReferenceEndpoint', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Configures the dev tunnel to expose a target endpoint. */ + withTunnelReference(targetEndpoint: EndpointReference): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withTunnelReferenceInternal(targetEndpoint)); + } + + /** @internal */ + private async _withTunnelReferenceAnonymousInternal(targetEndpoint: EndpointReference, allowAnonymous: boolean): Promise { + const rpcArgs: Record = { tunnelBuilder: this._handle, targetEndpoint, allowAnonymous }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.DevTunnels/withReferenceEndpointAnonymous', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Configures the dev tunnel to expose a target endpoint with access control. */ + withTunnelReferenceAnonymous(targetEndpoint: EndpointReference, allowAnonymous: boolean): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withTunnelReferenceAnonymousInternal(targetEndpoint, allowAnonymous)); + } + + /** @internal */ + private async _withAnonymousAccessInternal(): Promise { + const rpcArgs: Record = { tunnelBuilder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.DevTunnels/withAnonymousAccess', + rpcArgs + ); + return new DevTunnelResource(result, this._client); + } + + /** Configures the dev tunnel to allow anonymous access. */ + withAnonymousAccess(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._withAnonymousAccessInternal()); + } + + /** Gets the public endpoint exposed by the dev tunnel. */ + async getTunnelEndpoint(targetEndpointReference: EndpointReference): Promise { + const rpcArgs: Record = { tunnelBuilder: this._handle, targetEndpointReference }; + return await this._client.invokeCapability( + 'Aspire.Hosting.DevTunnels/getEndpointByEndpointReference', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for DevTunnelResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class DevTunnelResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DevTunnelResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Configures the dev tunnel to expose all endpoints on the referenced resource. */ + withTunnelReferenceAll(resourceBuilder: ResourceBuilderBase, allowAnonymous: boolean): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withTunnelReferenceAll(resourceBuilder, allowAnonymous))); + } + + /** Configures the dev tunnel to expose a target endpoint. */ + withTunnelReference(targetEndpoint: EndpointReference): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withTunnelReference(targetEndpoint))); + } + + /** Configures the dev tunnel to expose a target endpoint with access control. */ + withTunnelReferenceAnonymous(targetEndpoint: EndpointReference, allowAnonymous: boolean): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withTunnelReferenceAnonymous(targetEndpoint, allowAnonymous))); + } + + /** Configures the dev tunnel to allow anonymous access. */ + withAnonymousAccess(): DevTunnelResourcePromise { + return new DevTunnelResourcePromise(this._promise.then(obj => obj.withAnonymousAccess())); + } + + /** Gets the public endpoint exposed by the dev tunnel. */ + getTunnelEndpoint(targetEndpointReference: EndpointReference): Promise { + return this._promise.then(obj => obj.getTunnelEndpoint(targetEndpointReference)); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.DevTunnels/Aspire.Hosting.DevTunnels.DevTunnelResource', (handle, client) => new DevTunnelResource(handle as DevTunnelResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..2721acca1cf --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/apphost.ts @@ -0,0 +1,47 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// Test 1: Basic dev tunnel resource creation (addDevTunnel) +const tunnel = await builder.addDevTunnel("mytunnel"); + +// Test 2: addDevTunnel with tunnelId option +const tunnel2 = await builder.addDevTunnel("mytunnel2", { tunnelId: "custom-tunnel-id" }); + +// Test 3: withAnonymousAccess +await builder.addDevTunnel("anon-tunnel") + .withAnonymousAccess(); + +// Test 4: Add a container to reference its endpoints +const web = await builder.addContainer("web", "nginx") + .withHttpEndpoint({ port: 80 }); + +// Test 5: withTunnelReference with EndpointReference (expose a specific endpoint) +const webEndpoint = await web.getEndpoint("http"); +await tunnel.withTunnelReference(webEndpoint); + +// Test 6: withTunnelReferenceAnonymous with EndpointReference + allowAnonymous +const web2 = await builder.addContainer("web2", "nginx") + .withHttpEndpoint({ port: 8080 }); +const web2Endpoint = await web2.getEndpoint("http"); +await tunnel2.withTunnelReferenceAnonymous(web2Endpoint, true); + +// Test 7: withTunnelReferenceAll - expose all endpoints on a resource +const tunnel3 = await builder.addDevTunnel("all-endpoints-tunnel"); +const web3 = await builder.addContainer("web3", "nginx") + .withHttpEndpoint({ port: 80 }); +await tunnel3.withTunnelReferenceAll(web3, false); + +// Test 8: getTunnelEndpoint - get the public tunnel endpoint for a specific endpoint +const web4 = await builder.addContainer("web4", "nginx") + .withHttpEndpoint({ port: 80 }); +const web4Endpoint = await web4.getEndpoint("http"); +const tunnel4 = await builder.addDevTunnel("get-endpoint-tunnel"); +await tunnel4.withTunnelReference(web4Endpoint); +const _tunnelEndpoint = await tunnel4.getTunnelEndpoint(web4Endpoint); + +// Test 9: Chained configuration +await builder.addDevTunnel("chained-tunnel") + .withAnonymousAccess(); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.DevTunnels/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..b62948ab57c --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Garnet": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..350967db366 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +631BBDFB5C0199C5FFFC91CA20424E6F2B7E092C25EB887B9C5820C5FF3EB37A \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..b98f1b70441 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5514 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to GarnetResource */ +type GarnetResourceHandle = Handle<'Aspire.Hosting.Garnet/Aspire.Hosting.ApplicationModel.GarnetResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddGarnetOptions { + port?: number; + password?: ParameterResource; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithDataVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithPersistenceOptions { + interval?: number; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a Garnet container resource to the application model. */ + /** @internal */ + async _addGarnetInternal(name: string, port?: number, password?: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (port !== undefined) rpcArgs.port = port; + if (password !== undefined) rpcArgs.password = password; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Garnet/addGarnet', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + addGarnet(name: string, options?: AddGarnetOptions): GarnetResourcePromise { + const port = options?.port; + const password = options?.password; + return new GarnetResourcePromise(this._addGarnetInternal(name, port, password)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a Garnet container resource to the application model. */ + addGarnet(name: string, options?: AddGarnetOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.addGarnet(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// GarnetResource +// ============================================================================ + +export class GarnetResource extends ResourceBuilderBase { + constructor(handle: GarnetResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): GarnetResourcePromise { + const isReadOnly = options?.isReadOnly; + return new GarnetResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): GarnetResourcePromise { + const tag = options?.tag; + return new GarnetResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): GarnetResourcePromise { + return new GarnetResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): GarnetResourcePromise { + return new GarnetResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): GarnetResourcePromise { + return new GarnetResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): GarnetResourcePromise { + return new GarnetResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): GarnetResourcePromise { + return new GarnetResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): GarnetResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new GarnetResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): GarnetResourcePromise { + return new GarnetResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): GarnetResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new GarnetResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): GarnetResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new GarnetResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): GarnetResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new GarnetResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): GarnetResourcePromise { + return new GarnetResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): GarnetResourcePromise { + return new GarnetResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): GarnetResourcePromise { + const displayText = options?.displayText; + return new GarnetResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): GarnetResourcePromise { + const displayText = options?.displayText; + return new GarnetResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): GarnetResourcePromise { + return new GarnetResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): GarnetResourcePromise { + return new GarnetResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): GarnetResourcePromise { + const exitCode = options?.exitCode; + return new GarnetResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): GarnetResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new GarnetResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): GarnetResourcePromise { + const commandOptions = options?.commandOptions; + return new GarnetResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): GarnetResourcePromise { + return new GarnetResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): GarnetResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new GarnetResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Garnet/withDataVolume', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Exports WithDataVolume for polyglot app hosts. */ + withDataVolume(options?: WithDataVolumeOptions): GarnetResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new GarnetResourcePromise(this._withDataVolumeInternal(name, isReadOnly)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Garnet/withDataBindMount', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Exports WithDataBindMount for polyglot app hosts. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): GarnetResourcePromise { + const isReadOnly = options?.isReadOnly; + return new GarnetResourcePromise(this._withDataBindMountInternal(source, isReadOnly)); + } + + /** @internal */ + private async _withPersistenceInternal(interval?: number): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (interval !== undefined) rpcArgs.interval = interval; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Garnet/withPersistence', + rpcArgs + ); + return new GarnetResource(result, this._client); + } + + /** Exports WithPersistence for polyglot app hosts. */ + withPersistence(options?: WithPersistenceOptions): GarnetResourcePromise { + const interval = options?.interval; + return new GarnetResourcePromise(this._withPersistenceInternal(interval)); + } + +} + +/** + * Thenable wrapper for GarnetResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class GarnetResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: GarnetResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Exports WithDataVolume for polyglot app hosts. */ + withDataVolume(options?: WithDataVolumeOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Exports WithDataBindMount for polyglot app hosts. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withDataBindMount(source, options))); + } + + /** Exports WithPersistence for polyglot app hosts. */ + withPersistence(options?: WithPersistenceOptions): GarnetResourcePromise { + return new GarnetResourcePromise(this._promise.then(obj => obj.withPersistence(options))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Garnet/Aspire.Hosting.ApplicationModel.GarnetResource', (handle, client) => new GarnetResource(handle as GarnetResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..f8008c25074 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/apphost.ts @@ -0,0 +1,4 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Garnet/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..50026fd6e5e --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.GitHub.Models": "" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..aefe809b9a4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +C13880F095DBA862665782C34D611AD1BB6B65C79C0D482A6EB5C7CACE3CDB53 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..acbba8e2442 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5096 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to GitHubModelResource */ +type GitHubModelResourceHandle = Handle<'Aspire.Hosting.GitHub.Models/Aspire.Hosting.GitHub.Models.GitHubModelResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for GitHubModelName */ +export enum GitHubModelName { + AI21Jamba15Large = "AI21Jamba15Large", + CohereCommandA = "CohereCommandA", + CohereCommandR082024 = "CohereCommandR082024", + CohereCommandRPlus082024 = "CohereCommandRPlus082024", + DeepSeekR1 = "DeepSeekR1", + DeepSeekR10528 = "DeepSeekR10528", + DeepSeekV30324 = "DeepSeekV30324", + Llama4Maverick17B128EInstructFP8 = "Llama4Maverick17B128EInstructFP8", + Llama4Scout17B16EInstruct = "Llama4Scout17B16EInstruct", + Llama3211BVisionInstruct = "Llama3211BVisionInstruct", + Llama3290BVisionInstruct = "Llama3290BVisionInstruct", + Llama3370BInstruct = "Llama3370BInstruct", + MetaLlama31405BInstruct = "MetaLlama31405BInstruct", + MetaLlama318BInstruct = "MetaLlama318BInstruct", + MaiDSR1 = "MaiDSR1", + Phi4 = "Phi4", + Phi4MiniInstruct = "Phi4MiniInstruct", + Phi4MiniReasoning = "Phi4MiniReasoning", + Phi4MultimodalInstruct = "Phi4MultimodalInstruct", + Phi4Reasoning = "Phi4Reasoning", + Codestral2501 = "Codestral2501", + Ministral3B = "Ministral3B", + MistralMedium32505 = "MistralMedium32505", + MistralSmall31 = "MistralSmall31", + OpenAIGpt41 = "OpenAIGpt41", + OpenAIGpt41Mini = "OpenAIGpt41Mini", + OpenAIGpt41Nano = "OpenAIGpt41Nano", + OpenAIGpt4o = "OpenAIGpt4o", + OpenAIGpt4oMini = "OpenAIGpt4oMini", + OpenAIGpt5 = "OpenAIGpt5", + OpenAIGpt5ChatPreview = "OpenAIGpt5ChatPreview", + OpenAIGpt5Mini = "OpenAIGpt5Mini", + OpenAIGpt5Nano = "OpenAIGpt5Nano", + OpenAIO1 = "OpenAIO1", + OpenAIO1Mini = "OpenAIO1Mini", + OpenAIO1Preview = "OpenAIO1Preview", + OpenAIO3 = "OpenAIO3", + OpenAIO3Mini = "OpenAIO3Mini", + OpenAIO4Mini = "OpenAIO4Mini", + OpenAITextEmbedding3Large = "OpenAITextEmbedding3Large", + OpenAITextEmbedding3Small = "OpenAITextEmbedding3Small", + Grok3 = "Grok3", + Grok3Mini = "Grok3Mini", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddGitHubModelByIdOptions { + organization?: ParameterResource; +} + +export interface AddGitHubModelOptions { + organization?: ParameterResource; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a GitHub Model resource to the distributed application model. */ + /** @internal */ + async _addGitHubModelInternal(name: string, model: GitHubModelName, organization?: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name, model }; + if (organization !== undefined) rpcArgs.organization = organization; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.GitHub.Models/addGitHubModel', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + addGitHubModel(name: string, model: GitHubModelName, options?: AddGitHubModelOptions): GitHubModelResourcePromise { + const organization = options?.organization; + return new GitHubModelResourcePromise(this._addGitHubModelInternal(name, model, organization)); + } + + /** Adds a GitHub Model resource using a model identifier string. */ + /** @internal */ + async _addGitHubModelByIdInternal(name: string, modelId: string, organization?: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name, modelId }; + if (organization !== undefined) rpcArgs.organization = organization; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.GitHub.Models/addGitHubModelById', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + addGitHubModelById(name: string, modelId: string, options?: AddGitHubModelByIdOptions): GitHubModelResourcePromise { + const organization = options?.organization; + return new GitHubModelResourcePromise(this._addGitHubModelByIdInternal(name, modelId, organization)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a GitHub Model resource to the distributed application model. */ + addGitHubModel(name: string, model: GitHubModelName, options?: AddGitHubModelOptions): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.addGitHubModel(name, model, options))); + } + + /** Adds a GitHub Model resource using a model identifier string. */ + addGitHubModelById(name: string, modelId: string, options?: AddGitHubModelByIdOptions): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.addGitHubModelById(name, modelId, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + const tag = options?.tag; + return new ContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// GitHubModelResource +// ============================================================================ + +export class GitHubModelResource extends ResourceBuilderBase { + constructor(handle: GitHubModelResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): GitHubModelResourcePromise { + const displayText = options?.displayText; + return new GitHubModelResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): GitHubModelResourcePromise { + const displayText = options?.displayText; + return new GitHubModelResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): GitHubModelResourcePromise { + const commandOptions = options?.commandOptions; + return new GitHubModelResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withApiKeyInternal(apiKey: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, apiKey }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.GitHub.Models/withApiKey', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Configures the API key for the GitHub Model resource. */ + withApiKey(apiKey: ParameterResource): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._withApiKeyInternal(apiKey)); + } + + /** @internal */ + private async _enableHealthCheckInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.GitHub.Models/enableHealthCheck', + rpcArgs + ); + return new GitHubModelResource(result, this._client); + } + + /** Adds a health check for the GitHub Model resource. */ + enableHealthCheck(): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._enableHealthCheckInternal()); + } + +} + +/** + * Thenable wrapper for GitHubModelResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class GitHubModelResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: GitHubModelResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Configures the API key for the GitHub Model resource. */ + withApiKey(apiKey: ParameterResource): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.withApiKey(apiKey))); + } + + /** Adds a health check for the GitHub Model resource. */ + enableHealthCheck(): GitHubModelResourcePromise { + return new GitHubModelResourcePromise(this._promise.then(obj => obj.enableHealthCheck())); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.GitHub.Models/Aspire.Hosting.GitHub.Models.GitHubModelResource', (handle, client) => new GitHubModelResource(handle as GitHubModelResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..7bddd74beff --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,574 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + const result = await callback(...argArray); + // DTO writeback protocol: when a void callback returns undefined, we + // return the original args object so the .NET host can detect property + // mutations made by the callback and apply them back to the original + // C# DTO objects. DTO args are plain JS objects (not Handle wrappers), + // so any property changes the callback made are reflected in args. + // + // Non-void callbacks (result !== undefined) return their actual result. + // The .NET side only activates writeback for void delegates whose + // parameters include [AspireDto] types — all other cases discard the + // returned args object, so the extra wire payload is harmless. + // + // IMPORTANT: callbacks that intentionally return undefined will also + // trigger this path. For non-void delegate types, the C# proxy uses + // a result-unmarshalling path (not writeback), so returning args will + // cause an unmarshal error. Void callbacks should never return a + // meaningful value; non-void callbacks should always return one. + return result !== undefined ? result : args; + } + + // No positional params found — nothing to write back + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..837fb7d9a18 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/apphost.ts @@ -0,0 +1,30 @@ +import { createBuilder, GitHubModelName } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// 1) addGitHubModel — using the GitHubModelName enum +const githubModel = await builder.addGitHubModel("chat", GitHubModelName.OpenAIGpt4o); + +// 2) addGitHubModel — with organization parameter +const orgParam = await builder.addParameter("gh-org"); +const githubModelWithOrg = await builder.addGitHubModel("chat-org", GitHubModelName.OpenAIGpt4oMini, { organization: orgParam }); + +// 3) addGitHubModelById — using a model identifier string for models not in the enum +const customModel = await builder.addGitHubModelById("custom-chat", "custom-vendor/custom-model"); + +// 3) withApiKey — configure a custom API key parameter +const apiKey = await builder.addParameter("gh-api-key", { secret: true }); +await githubModel.withApiKey(apiKey); + +// 4) enableHealthCheck — integration-specific no-args health check +await githubModel.enableHealthCheck(); + +// 5) withReference — pass GitHubModelResource as a connection string source to a container +const container = await builder.addContainer("my-service", "mcr.microsoft.com/dotnet/samples:latest"); +await container.withReference(githubModel); + +// 6) withReference — pass GitHubModelResource as a source to another container with custom connection name +await container.withReference(githubModelWithOrg, { connectionName: "github-model-org" }); + +const app = await builder.build(); +await app.run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..00f6d3b5743 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.GitHub.Models/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts", ".modules/**/*.d.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..d83f12b8f4d --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Milvus": "" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..19ef9948bb9 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +9EFB61F16E182F3768B58F94109F169DE36E549231F384300B80FD166C7A010B \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..179677a0ced --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,6725 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to MilvusDatabaseResource */ +type MilvusDatabaseResourceHandle = Handle<'Aspire.Hosting.Milvus/Aspire.Hosting.ApplicationModel.MilvusDatabaseResource'>; + +/** Handle to AttuResource */ +type AttuResourceHandle = Handle<'Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.AttuResource'>; + +/** Handle to MilvusServerResource */ +type MilvusServerResourceHandle = Handle<'Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.MilvusServerResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddDatabaseOptions { + databaseName?: string; +} + +export interface AddMilvusOptions { + apiKey?: ParameterResource; + grpcPort?: number; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithAttuOptions { + configureContainer?: (obj: AttuResource) => Promise; + containerName?: string; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithDataVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a Milvus server resource to the distributed application model. */ + /** @internal */ + async _addMilvusInternal(name: string, apiKey?: ParameterResource, grpcPort?: number): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (apiKey !== undefined) rpcArgs.apiKey = apiKey; + if (grpcPort !== undefined) rpcArgs.grpcPort = grpcPort; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Milvus/addMilvus', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + addMilvus(name: string, options?: AddMilvusOptions): MilvusServerResourcePromise { + const apiKey = options?.apiKey; + const grpcPort = options?.grpcPort; + return new MilvusServerResourcePromise(this._addMilvusInternal(name, apiKey, grpcPort)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a Milvus server resource to the distributed application model. */ + addMilvus(name: string, options?: AddMilvusOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.addMilvus(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// AttuResource +// ============================================================================ + +export class AttuResource extends ResourceBuilderBase { + constructor(handle: AttuResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AttuResourcePromise { + const isReadOnly = options?.isReadOnly; + return new AttuResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AttuResourcePromise { + return new AttuResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AttuResourcePromise { + return new AttuResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AttuResourcePromise { + return new AttuResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AttuResourcePromise { + const tag = options?.tag; + return new AttuResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AttuResourcePromise { + return new AttuResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AttuResourcePromise { + return new AttuResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AttuResourcePromise { + return new AttuResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): AttuResourcePromise { + return new AttuResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AttuResourcePromise { + return new AttuResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AttuResourcePromise { + return new AttuResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): AttuResourcePromise { + return new AttuResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AttuResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new AttuResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AttuResourcePromise { + return new AttuResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AttuResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new AttuResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AttuResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AttuResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AttuResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new AttuResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AttuResourcePromise { + return new AttuResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AttuResourcePromise { + return new AttuResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AttuResourcePromise { + const displayText = options?.displayText; + return new AttuResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AttuResourcePromise { + const displayText = options?.displayText; + return new AttuResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AttuResourcePromise { + return new AttuResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AttuResourcePromise { + return new AttuResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AttuResourcePromise { + const exitCode = options?.exitCode; + return new AttuResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AttuResourcePromise { + return new AttuResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AttuResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new AttuResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AttuResourcePromise { + const commandOptions = options?.commandOptions; + return new AttuResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AttuResourcePromise { + return new AttuResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new AttuResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AttuResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new AttuResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for AttuResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AttuResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AttuResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): AttuResourcePromise { + return new AttuResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// MilvusDatabaseResource +// ============================================================================ + +export class MilvusDatabaseResource extends ResourceBuilderBase { + constructor(handle: MilvusDatabaseResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MilvusDatabaseResourcePromise { + const displayText = options?.displayText; + return new MilvusDatabaseResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MilvusDatabaseResourcePromise { + const displayText = options?.displayText; + return new MilvusDatabaseResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MilvusDatabaseResourcePromise { + const commandOptions = options?.commandOptions; + return new MilvusDatabaseResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for MilvusDatabaseResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class MilvusDatabaseResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: MilvusDatabaseResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// MilvusServerResource +// ============================================================================ + +export class MilvusServerResource extends ResourceBuilderBase { + constructor(handle: MilvusServerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): MilvusServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new MilvusServerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): MilvusServerResourcePromise { + const tag = options?.tag; + return new MilvusServerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): MilvusServerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new MilvusServerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): MilvusServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new MilvusServerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): MilvusServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new MilvusServerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): MilvusServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new MilvusServerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MilvusServerResourcePromise { + const displayText = options?.displayText; + return new MilvusServerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MilvusServerResourcePromise { + const displayText = options?.displayText; + return new MilvusServerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): MilvusServerResourcePromise { + const exitCode = options?.exitCode; + return new MilvusServerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): MilvusServerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new MilvusServerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MilvusServerResourcePromise { + const commandOptions = options?.commandOptions; + return new MilvusServerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): MilvusServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new MilvusServerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _addDatabaseInternal(name: string, databaseName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (databaseName !== undefined) rpcArgs.databaseName = databaseName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Milvus/addDatabase', + rpcArgs + ); + return new MilvusDatabaseResource(result, this._client); + } + + /** Adds a Milvus database resource to a Milvus server resource. */ + addDatabase(name: string, options?: AddDatabaseOptions): MilvusDatabaseResourcePromise { + const databaseName = options?.databaseName; + return new MilvusDatabaseResourcePromise(this._addDatabaseInternal(name, databaseName)); + } + + /** @internal */ + private async _withAttuInternal(configureContainer?: (obj: AttuResource) => Promise, containerName?: string): Promise { + const configureContainerId = configureContainer ? registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as AttuResourceHandle; + const obj = new AttuResource(objHandle, this._client); + await configureContainer(obj); + }) : undefined; + const rpcArgs: Record = { builder: this._handle }; + if (configureContainer !== undefined) rpcArgs.configureContainer = configureContainerId; + if (containerName !== undefined) rpcArgs.containerName = containerName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Milvus/withAttu', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds the Attu administration tool for Milvus. */ + withAttu(options?: WithAttuOptions): MilvusServerResourcePromise { + const configureContainer = options?.configureContainer; + const containerName = options?.containerName; + return new MilvusServerResourcePromise(this._withAttuInternal(configureContainer, containerName)); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Milvus/withDataVolume', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Adds a persistent data volume to the Milvus server resource. */ + withDataVolume(options?: WithDataVolumeOptions): MilvusServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new MilvusServerResourcePromise(this._withDataVolumeInternal(name, isReadOnly)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Milvus/withDataBindMount', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Mounts a host directory as the Milvus data directory. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): MilvusServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new MilvusServerResourcePromise(this._withDataBindMountInternal(source, isReadOnly)); + } + + /** @internal */ + private async _withConfigurationFileInternal(configurationFilePath: string): Promise { + const rpcArgs: Record = { builder: this._handle, configurationFilePath }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Milvus/withConfigurationFile', + rpcArgs + ); + return new MilvusServerResource(result, this._client); + } + + /** Copies a Milvus configuration file into the container. */ + withConfigurationFile(configurationFilePath: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._withConfigurationFileInternal(configurationFilePath)); + } + +} + +/** + * Thenable wrapper for MilvusServerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class MilvusServerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: MilvusServerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds a Milvus database resource to a Milvus server resource. */ + addDatabase(name: string, options?: AddDatabaseOptions): MilvusDatabaseResourcePromise { + return new MilvusDatabaseResourcePromise(this._promise.then(obj => obj.addDatabase(name, options))); + } + + /** Adds the Attu administration tool for Milvus. */ + withAttu(options?: WithAttuOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withAttu(options))); + } + + /** Adds a persistent data volume to the Milvus server resource. */ + withDataVolume(options?: WithDataVolumeOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Mounts a host directory as the Milvus data directory. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withDataBindMount(source, options))); + } + + /** Copies a Milvus configuration file into the container. */ + withConfigurationFile(configurationFilePath: string): MilvusServerResourcePromise { + return new MilvusServerResourcePromise(this._promise.then(obj => obj.withConfigurationFile(configurationFilePath))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.AttuResource', (handle, client) => new AttuResource(handle as AttuResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Milvus/Aspire.Hosting.ApplicationModel.MilvusDatabaseResource', (handle, client) => new MilvusDatabaseResource(handle as MilvusDatabaseResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.MilvusServerResource', (handle, client) => new MilvusServerResource(handle as MilvusServerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..473f9fe21fb --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/apphost.ts @@ -0,0 +1,69 @@ +// Aspire TypeScript AppHost — Milvus integration validation +// Exercises every exported member of Aspire.Hosting.Milvus + +import { createBuilder, ContainerLifetime } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// ── 1. addMilvus: basic Milvus server resource ───────────────────────────── +const milvus = await builder.addMilvus("milvus"); + +// ── 2. addMilvus: with custom apiKey parameter ───────────────────────────── +const customKey = await builder.addParameter("milvus-key", { secret: true }); +const milvus2 = await builder.addMilvus("milvus2", { apiKey: customKey }); + +// ── 3. addMilvus: with explicit gRPC port ────────────────────────────────── +await builder.addMilvus("milvus3", { grpcPort: 19531 }); + +// ── 4. addDatabase: add database to Milvus server ────────────────────────── +const db = await milvus.addDatabase("mydb"); + +// ── 5. addDatabase: with custom database name ────────────────────────────── +await milvus.addDatabase("db2", { databaseName: "customdb" }); + +// ── 6. withAttu: add Attu administration tool ────────────────────────────── +await milvus.withAttu(); + +// ── 7. withAttu: with container name ──────────────────────────────────────── +await milvus2.withAttu({ containerName: "my-attu" }); + +// ── 8. withAttu: with configureContainer callback ────────────────────────── +await builder.addMilvus("milvus-attu-cfg") + .withAttu({ + configureContainer: async (container) => { + await container.withHttpEndpoint({ port: 3001 }); + } + }); + +// ── 9. withDataVolume: persistent data volume ────────────────────────────── +await milvus.withDataVolume(); + +// ── 10. withDataVolume: with custom name ──────────────────────────────────── +await milvus2.withDataVolume({ name: "milvus-data" }); + +// ── 11. withDataBindMount: bind mount for data ───────────────────────────── +await builder.addMilvus("milvus-bind") + .withDataBindMount("./milvus-data"); + +// ── 12. withDataBindMount: with read-only flag ───────────────────────────── +await builder.addMilvus("milvus-bind-ro") + .withDataBindMount("./milvus-data-ro", { isReadOnly: true }); + +// ── 13. withConfigurationFile: custom milvus.yaml ────────────────────────── +await builder.addMilvus("milvus-cfg") + .withConfigurationFile("./milvus.yaml"); + +// ── 14. Fluent chaining: multiple With* methods ──────────────────────────── +await builder.addMilvus("milvus-chained") + .withLifetime(ContainerLifetime.Persistent) + .withDataVolume({ name: "milvus-chained-data" }) + .withAttu(); + +// ── 15. withReference: use Milvus database from a container resource ─────── +const api = await builder.addContainer("api", "myregistry/myapp"); +await api.withReference(db); + +// ── 16. withReference: use Milvus server directly ────────────────────────── +await api.withReference(milvus); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Milvus/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..9fc9e19f96a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.MySql": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..ce0ce5c46be --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +C059C1DD2931ECF547C421DC89FBA611588AFAE7F282D848F2B58393737D1D37 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..4a363adc7c7 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,6791 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to MySqlDatabaseResource */ +type MySqlDatabaseResourceHandle = Handle<'Aspire.Hosting.MySql/Aspire.Hosting.ApplicationModel.MySqlDatabaseResource'>; + +/** Handle to MySqlServerResource */ +type MySqlServerResourceHandle = Handle<'Aspire.Hosting.MySql/Aspire.Hosting.ApplicationModel.MySqlServerResource'>; + +/** Handle to PhpMyAdminContainerResource */ +type PhpMyAdminContainerResourceHandle = Handle<'Aspire.Hosting.MySql/Aspire.Hosting.MySql.PhpMyAdminContainerResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddDatabaseOptions { + databaseName?: string; +} + +export interface AddMySqlOptions { + password?: ParameterResource; + port?: number; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithDataVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHostPortOptions { + port?: number; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithPhpMyAdminOptions { + configureContainer?: (obj: PhpMyAdminContainerResource) => Promise; + containerName?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a MySQL server resource */ + /** @internal */ + async _addMySqlInternal(name: string, password?: ParameterResource, port?: number): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (password !== undefined) rpcArgs.password = password; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/addMySql', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + addMySql(name: string, options?: AddMySqlOptions): MySqlServerResourcePromise { + const password = options?.password; + const port = options?.port; + return new MySqlServerResourcePromise(this._addMySqlInternal(name, password, port)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a MySQL server resource */ + addMySql(name: string, options?: AddMySqlOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.addMySql(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// MySqlDatabaseResource +// ============================================================================ + +export class MySqlDatabaseResource extends ResourceBuilderBase { + constructor(handle: MySqlDatabaseResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MySqlDatabaseResourcePromise { + const displayText = options?.displayText; + return new MySqlDatabaseResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MySqlDatabaseResourcePromise { + const displayText = options?.displayText; + return new MySqlDatabaseResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MySqlDatabaseResourcePromise { + const commandOptions = options?.commandOptions; + return new MySqlDatabaseResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withCreationScriptInternal(script: string): Promise { + const rpcArgs: Record = { builder: this._handle, script }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/withCreationScript', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Defines the SQL script for database creation */ + withCreationScript(script: string): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._withCreationScriptInternal(script)); + } + +} + +/** + * Thenable wrapper for MySqlDatabaseResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class MySqlDatabaseResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: MySqlDatabaseResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Defines the SQL script for database creation */ + withCreationScript(script: string): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.withCreationScript(script))); + } + +} + +// ============================================================================ +// MySqlServerResource +// ============================================================================ + +export class MySqlServerResource extends ResourceBuilderBase { + constructor(handle: MySqlServerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): MySqlServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new MySqlServerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): MySqlServerResourcePromise { + const tag = options?.tag; + return new MySqlServerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): MySqlServerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new MySqlServerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): MySqlServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new MySqlServerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): MySqlServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new MySqlServerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): MySqlServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new MySqlServerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MySqlServerResourcePromise { + const displayText = options?.displayText; + return new MySqlServerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MySqlServerResourcePromise { + const displayText = options?.displayText; + return new MySqlServerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): MySqlServerResourcePromise { + const exitCode = options?.exitCode; + return new MySqlServerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): MySqlServerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new MySqlServerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MySqlServerResourcePromise { + const commandOptions = options?.commandOptions; + return new MySqlServerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): MySqlServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new MySqlServerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _addDatabaseInternal(name: string, databaseName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (databaseName !== undefined) rpcArgs.databaseName = databaseName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/addDatabase', + rpcArgs + ); + return new MySqlDatabaseResource(result, this._client); + } + + /** Adds a MySQL database */ + addDatabase(name: string, options?: AddDatabaseOptions): MySqlDatabaseResourcePromise { + const databaseName = options?.databaseName; + return new MySqlDatabaseResourcePromise(this._addDatabaseInternal(name, databaseName)); + } + + /** @internal */ + private async _withPasswordInternal(password: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, password }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/withPassword', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Configures the MySQL password */ + withPassword(password: ParameterResource): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withPasswordInternal(password)); + } + + /** @internal */ + private async _withPhpMyAdminInternal(configureContainer?: (obj: PhpMyAdminContainerResource) => Promise, containerName?: string): Promise { + const configureContainerId = configureContainer ? registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as PhpMyAdminContainerResourceHandle; + const obj = new PhpMyAdminContainerResource(objHandle, this._client); + await configureContainer(obj); + }) : undefined; + const rpcArgs: Record = { builder: this._handle }; + if (configureContainer !== undefined) rpcArgs.configureContainer = configureContainerId; + if (containerName !== undefined) rpcArgs.containerName = containerName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/withPhpMyAdmin', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds phpMyAdmin management UI */ + withPhpMyAdmin(options?: WithPhpMyAdminOptions): MySqlServerResourcePromise { + const configureContainer = options?.configureContainer; + const containerName = options?.containerName; + return new MySqlServerResourcePromise(this._withPhpMyAdminInternal(configureContainer, containerName)); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/withDataVolume', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a data volume for MySQL */ + withDataVolume(options?: WithDataVolumeOptions): MySqlServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new MySqlServerResourcePromise(this._withDataVolumeInternal(name, isReadOnly)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/withDataBindMount', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Adds a data bind mount for MySQL */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): MySqlServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new MySqlServerResourcePromise(this._withDataBindMountInternal(source, isReadOnly)); + } + + /** @internal */ + private async _withInitFilesInternal(source: string): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/withInitFiles', + rpcArgs + ); + return new MySqlServerResource(result, this._client); + } + + /** Copies init files to MySQL */ + withInitFiles(source: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._withInitFilesInternal(source)); + } + +} + +/** + * Thenable wrapper for MySqlServerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class MySqlServerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: MySqlServerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds a MySQL database */ + addDatabase(name: string, options?: AddDatabaseOptions): MySqlDatabaseResourcePromise { + return new MySqlDatabaseResourcePromise(this._promise.then(obj => obj.addDatabase(name, options))); + } + + /** Configures the MySQL password */ + withPassword(password: ParameterResource): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withPassword(password))); + } + + /** Adds phpMyAdmin management UI */ + withPhpMyAdmin(options?: WithPhpMyAdminOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withPhpMyAdmin(options))); + } + + /** Adds a data volume for MySQL */ + withDataVolume(options?: WithDataVolumeOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Adds a data bind mount for MySQL */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withDataBindMount(source, options))); + } + + /** Copies init files to MySQL */ + withInitFiles(source: string): MySqlServerResourcePromise { + return new MySqlServerResourcePromise(this._promise.then(obj => obj.withInitFiles(source))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// PhpMyAdminContainerResource +// ============================================================================ + +export class PhpMyAdminContainerResource extends ResourceBuilderBase { + constructor(handle: PhpMyAdminContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): PhpMyAdminContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new PhpMyAdminContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): PhpMyAdminContainerResourcePromise { + const tag = options?.tag; + return new PhpMyAdminContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): PhpMyAdminContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new PhpMyAdminContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): PhpMyAdminContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new PhpMyAdminContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): PhpMyAdminContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new PhpMyAdminContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): PhpMyAdminContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new PhpMyAdminContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): PhpMyAdminContainerResourcePromise { + const displayText = options?.displayText; + return new PhpMyAdminContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): PhpMyAdminContainerResourcePromise { + const displayText = options?.displayText; + return new PhpMyAdminContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): PhpMyAdminContainerResourcePromise { + const exitCode = options?.exitCode; + return new PhpMyAdminContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): PhpMyAdminContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new PhpMyAdminContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): PhpMyAdminContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new PhpMyAdminContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): PhpMyAdminContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new PhpMyAdminContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withHostPortInternal(port?: number): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.MySql/withHostPort', + rpcArgs + ); + return new PhpMyAdminContainerResource(result, this._client); + } + + /** Sets the host port for phpMyAdmin */ + withHostPort(options?: WithHostPortOptions): PhpMyAdminContainerResourcePromise { + const port = options?.port; + return new PhpMyAdminContainerResourcePromise(this._withHostPortInternal(port)); + } + +} + +/** + * Thenable wrapper for PhpMyAdminContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class PhpMyAdminContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: PhpMyAdminContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Sets the host port for phpMyAdmin */ + withHostPort(options?: WithHostPortOptions): PhpMyAdminContainerResourcePromise { + return new PhpMyAdminContainerResourcePromise(this._promise.then(obj => obj.withHostPort(options))); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.MySql/Aspire.Hosting.ApplicationModel.MySqlDatabaseResource', (handle, client) => new MySqlDatabaseResource(handle as MySqlDatabaseResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.MySql/Aspire.Hosting.ApplicationModel.MySqlServerResource', (handle, client) => new MySqlServerResource(handle as MySqlServerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.MySql/Aspire.Hosting.MySql.PhpMyAdminContainerResource', (handle, client) => new PhpMyAdminContainerResource(handle as PhpMyAdminContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..32af33c0ca5 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/apphost.ts @@ -0,0 +1,23 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); +const rootPassword = await builder.addParameter('mysql-root-password', { secret: true }); +const mysql = await builder.addMySql('mysql', { password: rootPassword, port: 3306 }); + +await mysql + .withPassword(rootPassword) + .withDataVolume({ name: 'mysql-data' }) + .withDataBindMount('.', { isReadOnly: true }) + .withInitFiles('.'); + +await mysql.withPhpMyAdmin({ + containerName: 'phpmyadmin', + configureContainer: async (container) => { + await container.withHostPort({ port: 8080 }); + } +}); + +const db = await mysql.addDatabase('appdb', { databaseName: 'appdb' }); +await db.withCreationScript('CREATE DATABASE IF NOT EXISTS appdb;'); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.MySql/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..942d97cb8dd --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Nats": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..b18442cc6ec --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +BA82BCA5B4BE2904A61C1F7B2680F9143C797E08051DC6948D08D41A2F137904 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..0911d135745 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5511 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to NatsServerResource */ +type NatsServerResourceHandle = Handle<'Aspire.Hosting.Nats/Aspire.Hosting.ApplicationModel.NatsServerResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddNatsOptions { + port?: number; + userName?: ParameterResource; + password?: ParameterResource; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithDataVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a NATS server resource to the application model. */ + /** @internal */ + async _addNatsInternal(name: string, port?: number, userName?: ParameterResource, password?: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (port !== undefined) rpcArgs.port = port; + if (userName !== undefined) rpcArgs.userName = userName; + if (password !== undefined) rpcArgs.password = password; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Nats/addNats', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + addNats(name: string, options?: AddNatsOptions): NatsServerResourcePromise { + const port = options?.port; + const userName = options?.userName; + const password = options?.password; + return new NatsServerResourcePromise(this._addNatsInternal(name, port, userName, password)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a NATS server resource to the application model. */ + addNats(name: string, options?: AddNatsOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.addNats(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// NatsServerResource +// ============================================================================ + +export class NatsServerResource extends ResourceBuilderBase { + constructor(handle: NatsServerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): NatsServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new NatsServerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): NatsServerResourcePromise { + const tag = options?.tag; + return new NatsServerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): NatsServerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new NatsServerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): NatsServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new NatsServerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): NatsServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new NatsServerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): NatsServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new NatsServerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): NatsServerResourcePromise { + const displayText = options?.displayText; + return new NatsServerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): NatsServerResourcePromise { + const displayText = options?.displayText; + return new NatsServerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): NatsServerResourcePromise { + const exitCode = options?.exitCode; + return new NatsServerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): NatsServerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new NatsServerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): NatsServerResourcePromise { + const commandOptions = options?.commandOptions; + return new NatsServerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): NatsServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new NatsServerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withJetStreamInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Nats/withJetStream', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Exports WithJetStream for polyglot app hosts. */ + withJetStream(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._withJetStreamInternal()); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Nats/withDataVolume', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Exports WithDataVolume for polyglot app hosts. */ + withDataVolume(options?: WithDataVolumeOptions): NatsServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new NatsServerResourcePromise(this._withDataVolumeInternal(name, isReadOnly)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Nats/withDataBindMount', + rpcArgs + ); + return new NatsServerResource(result, this._client); + } + + /** Exports WithDataBindMount for polyglot app hosts. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): NatsServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new NatsServerResourcePromise(this._withDataBindMountInternal(source, isReadOnly)); + } + +} + +/** + * Thenable wrapper for NatsServerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class NatsServerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: NatsServerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Exports WithJetStream for polyglot app hosts. */ + withJetStream(): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withJetStream())); + } + + /** Exports WithDataVolume for polyglot app hosts. */ + withDataVolume(options?: WithDataVolumeOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Exports WithDataBindMount for polyglot app hosts. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): NatsServerResourcePromise { + return new NatsServerResourcePromise(this._promise.then(obj => obj.withDataBindMount(source, options))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Nats/Aspire.Hosting.ApplicationModel.NatsServerResource', (handle, client) => new NatsServerResource(handle as NatsServerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..236c7ccf932 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/apphost.ts @@ -0,0 +1,42 @@ +// Aspire TypeScript AppHost — NATS integration validation +// Exercises all [AspireExport] methods for Aspire.Hosting.Nats + +import { createBuilder, ContainerLifetime } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// addNats — factory method with default options +const nats = await builder.addNats("messaging"); + +// withJetStream — enable JetStream support +await nats.withJetStream(); + +// withDataVolume — add persistent data volume +await nats.withDataVolume(); + +// withDataVolume — with custom name and readOnly option +const nats2 = await builder.addNats("messaging2", { port: 4223 }) + .withJetStream() + .withDataVolume({ name: "nats-data", isReadOnly: false }) + .withLifetime(ContainerLifetime.Persistent); + +// withDataBindMount — bind mount a host directory +const nats3 = await builder.addNats("messaging3"); +await nats3.withDataBindMount("/tmp/nats-data"); + +// addNats — with custom userName and password parameters +const customUser = await builder.addParameter("nats-user"); +const customPass = await builder.addParameter("nats-pass", { secret: true }); +const nats4 = await builder.addNats("messaging4", { + userName: customUser, + password: customPass, +}); + +// withReference — a container referencing a NATS resource (connection string) +const consumer = await builder.addContainer("consumer", "myimage"); +await consumer.withReference(nats); + +// withServiceReference — service discovery reference +await consumer.withServiceReference(nats); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..00f6d3b5743 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Nats/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts", ".modules/**/*.d.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..be31ad53336 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.OpenAI": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..f6b9a8c9468 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +039E22BEBD11F9200A87529D869A2C51F12C061E9B03BB26B6D96C3940A1D5C5 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..21aaf648879 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5148 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to OpenAIModelResource */ +type OpenAIModelResourceHandle = Handle<'Aspire.Hosting.OpenAI/Aspire.Hosting.OpenAI.OpenAIModelResource'>; + +/** Handle to OpenAIResource */ +type OpenAIResourceHandle = Handle<'Aspire.Hosting.OpenAI/Aspire.Hosting.OpenAI.OpenAIResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Exports AddOpenAI for polyglot app hosts. */ + /** @internal */ + async _addOpenAIInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.OpenAI/addOpenAI', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + addOpenAI(name: string): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._addOpenAIInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Exports AddOpenAI for polyglot app hosts. */ + addOpenAI(name: string): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.addOpenAI(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + const tag = options?.tag; + return new ContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// OpenAIModelResource +// ============================================================================ + +export class OpenAIModelResource extends ResourceBuilderBase { + constructor(handle: OpenAIModelResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OpenAIModelResourcePromise { + const displayText = options?.displayText; + return new OpenAIModelResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OpenAIModelResourcePromise { + const displayText = options?.displayText; + return new OpenAIModelResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OpenAIModelResourcePromise { + const commandOptions = options?.commandOptions; + return new OpenAIModelResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for OpenAIModelResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class OpenAIModelResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: OpenAIModelResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// OpenAIResource +// ============================================================================ + +export class OpenAIResource extends ResourceBuilderBase { + constructor(handle: OpenAIResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OpenAIResourcePromise { + const displayText = options?.displayText; + return new OpenAIResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OpenAIResourcePromise { + const displayText = options?.displayText; + return new OpenAIResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OpenAIResourcePromise { + const commandOptions = options?.commandOptions; + return new OpenAIResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _addModelInternal(name: string, model: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, model }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.OpenAI/addModel', + rpcArgs + ); + return new OpenAIModelResource(result, this._client); + } + + /** Exports AddModel for polyglot app hosts. */ + addModel(name: string, model: string): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._addModelInternal(name, model)); + } + + /** @internal */ + private async _withEndpointInternal(endpoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, endpoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.OpenAI/withEndpoint', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Exports WithEndpoint for polyglot app hosts. */ + withEndpoint(endpoint: string): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._withEndpointInternal(endpoint)); + } + + /** @internal */ + private async _withApiKeyInternal(apiKey: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, apiKey }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.OpenAI/withApiKey', + rpcArgs + ); + return new OpenAIResource(result, this._client); + } + + /** Exports WithApiKey for polyglot app hosts. */ + withApiKey(apiKey: ParameterResource): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._withApiKeyInternal(apiKey)); + } + +} + +/** + * Thenable wrapper for OpenAIResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class OpenAIResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: OpenAIResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Exports AddModel for polyglot app hosts. */ + addModel(name: string, model: string): OpenAIModelResourcePromise { + return new OpenAIModelResourcePromise(this._promise.then(obj => obj.addModel(name, model))); + } + + /** Exports WithEndpoint for polyglot app hosts. */ + withEndpoint(endpoint: string): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withEndpoint(endpoint))); + } + + /** Exports WithApiKey for polyglot app hosts. */ + withApiKey(apiKey: ParameterResource): OpenAIResourcePromise { + return new OpenAIResourcePromise(this._promise.then(obj => obj.withApiKey(apiKey))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.OpenAI/Aspire.Hosting.OpenAI.OpenAIModelResource', (handle, client) => new OpenAIModelResource(handle as OpenAIModelResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.OpenAI/Aspire.Hosting.OpenAI.OpenAIResource', (handle, client) => new OpenAIResource(handle as OpenAIResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..ab14ba1e839 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/apphost.ts @@ -0,0 +1,12 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const apiKey = await builder.addParameter("openai-api-key", { secret: true }); +const openai = await builder.addOpenAI("openai") + .withEndpoint("https://api.openai.com/v1") + .withApiKey(apiKey); + +await openai.addModel("chat-model", "gpt-4o-mini"); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.OpenAI/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..6ae08a9e585 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Oracle": "" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..77246f8bf0f --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +3351878CB6DB6FB990F1DCDC7A36F7A49F12AF937D99C1F87A559F6AC3007B8A \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..9fbd46dd96e --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5971 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to OracleDatabaseResource */ +type OracleDatabaseResourceHandle = Handle<'Aspire.Hosting.Oracle/Aspire.Hosting.ApplicationModel.OracleDatabaseResource'>; + +/** Handle to OracleDatabaseServerResource */ +type OracleDatabaseServerResourceHandle = Handle<'Aspire.Hosting.Oracle/Aspire.Hosting.ApplicationModel.OracleDatabaseServerResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddDatabaseOptions { + databaseName?: string; +} + +export interface AddOracleOptions { + password?: ParameterResource; + port?: number; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataVolumeOptions { + name?: string; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds an Oracle server resource to the distributed application model. */ + /** @internal */ + async _addOracleInternal(name: string, password?: ParameterResource, port?: number): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (password !== undefined) rpcArgs.password = password; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Oracle/addOracle', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + addOracle(name: string, options?: AddOracleOptions): OracleDatabaseServerResourcePromise { + const password = options?.password; + const port = options?.port; + return new OracleDatabaseServerResourcePromise(this._addOracleInternal(name, password, port)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds an Oracle server resource to the distributed application model. */ + addOracle(name: string, options?: AddOracleOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.addOracle(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// OracleDatabaseResource +// ============================================================================ + +export class OracleDatabaseResource extends ResourceBuilderBase { + constructor(handle: OracleDatabaseResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** Gets the Parent property */ + parent = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseResource.parent', + { context: this._handle } + ); + return new OracleDatabaseServerResource(handle, this._client); + }, + }; + + /** Gets the UriExpression property */ + uriExpression = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseResource.uriExpression', + { context: this._handle } + ); + return new ReferenceExpression(handle, this._client); + }, + }; + + /** Gets the JdbcConnectionString property */ + jdbcConnectionString = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseResource.jdbcConnectionString', + { context: this._handle } + ); + return new ReferenceExpression(handle, this._client); + }, + }; + + /** Gets the DatabaseName property */ + databaseName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseResource.databaseName', + { context: this._handle } + ); + }, + }; + + /** Gets the Name property */ + name = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseResource.name', + { context: this._handle } + ); + }, + }; + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OracleDatabaseResourcePromise { + const displayText = options?.displayText; + return new OracleDatabaseResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OracleDatabaseResourcePromise { + const displayText = options?.displayText; + return new OracleDatabaseResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OracleDatabaseResourcePromise { + const commandOptions = options?.commandOptions; + return new OracleDatabaseResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for OracleDatabaseResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class OracleDatabaseResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: OracleDatabaseResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// OracleDatabaseServerResource +// ============================================================================ + +export class OracleDatabaseServerResource extends ResourceBuilderBase { + constructor(handle: OracleDatabaseServerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** Gets the PrimaryEndpoint property */ + primaryEndpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.primaryEndpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.host', + { context: this._handle } + ); + return new EndpointReferenceExpression(handle, this._client); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.port', + { context: this._handle } + ); + return new EndpointReferenceExpression(handle, this._client); + }, + }; + + /** Gets the UserNameReference property */ + userNameReference = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.userNameReference', + { context: this._handle } + ); + return new ReferenceExpression(handle, this._client); + }, + }; + + /** Gets the UriExpression property */ + uriExpression = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.uriExpression', + { context: this._handle } + ); + return new ReferenceExpression(handle, this._client); + }, + }; + + /** Gets the JdbcConnectionString property */ + jdbcConnectionString = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.jdbcConnectionString', + { context: this._handle } + ); + return new ReferenceExpression(handle, this._client); + }, + }; + + /** Gets the Databases property */ + private _databases?: AspireDict; + get databases(): AspireDict { + if (!this._databases) { + this._databases = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.databases', + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.databases' + ); + } + return this._databases; + } + + /** Gets the Entrypoint property */ + entrypoint = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.entrypoint', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.setEntrypoint', + { context: this._handle, value } + ); + } + }; + + /** Gets the ShellExecution property */ + shellExecution = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.shellExecution', + { context: this._handle } + ); + }, + set: async (value: boolean): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.setShellExecution', + { context: this._handle, value } + ); + } + }; + + /** Gets the Name property */ + name = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/OracleDatabaseServerResource.name', + { context: this._handle } + ); + }, + }; + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): OracleDatabaseServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new OracleDatabaseServerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): OracleDatabaseServerResourcePromise { + const tag = options?.tag; + return new OracleDatabaseServerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): OracleDatabaseServerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new OracleDatabaseServerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): OracleDatabaseServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new OracleDatabaseServerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): OracleDatabaseServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new OracleDatabaseServerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): OracleDatabaseServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new OracleDatabaseServerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OracleDatabaseServerResourcePromise { + const displayText = options?.displayText; + return new OracleDatabaseServerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OracleDatabaseServerResourcePromise { + const displayText = options?.displayText; + return new OracleDatabaseServerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): OracleDatabaseServerResourcePromise { + const exitCode = options?.exitCode; + return new OracleDatabaseServerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): OracleDatabaseServerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new OracleDatabaseServerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OracleDatabaseServerResourcePromise { + const commandOptions = options?.commandOptions; + return new OracleDatabaseServerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): OracleDatabaseServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new OracleDatabaseServerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _addDatabaseInternal(name: string, databaseName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (databaseName !== undefined) rpcArgs.databaseName = databaseName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Oracle/addDatabase', + rpcArgs + ); + return new OracleDatabaseResource(result, this._client); + } + + /** Adds an Oracle database resource to an Oracle server resource. */ + addDatabase(name: string, options?: AddDatabaseOptions): OracleDatabaseResourcePromise { + const databaseName = options?.databaseName; + return new OracleDatabaseResourcePromise(this._addDatabaseInternal(name, databaseName)); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Oracle/withDataVolume', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Adds a persistent data volume to the Oracle server resource. */ + withDataVolume(options?: WithDataVolumeOptions): OracleDatabaseServerResourcePromise { + const name = options?.name; + return new OracleDatabaseServerResourcePromise(this._withDataVolumeInternal(name)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Oracle/withDataBindMount', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Mounts a host directory as the Oracle data directory. */ + withDataBindMount(source: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withDataBindMountInternal(source)); + } + + /** @internal */ + private async _withInitFilesInternal(source: string): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Oracle/withInitFiles', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Copies initialization files into the Oracle container. */ + withInitFiles(source: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withInitFilesInternal(source)); + } + + /** @internal */ + private async _withDbSetupBindMountInternal(source: string): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Oracle/withDbSetupBindMount', + rpcArgs + ); + return new OracleDatabaseServerResource(result, this._client); + } + + /** Mounts a host directory as the Oracle DB setup directory. */ + withDbSetupBindMount(source: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._withDbSetupBindMountInternal(source)); + } + +} + +/** + * Thenable wrapper for OracleDatabaseServerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class OracleDatabaseServerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: OracleDatabaseServerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds an Oracle database resource to an Oracle server resource. */ + addDatabase(name: string, options?: AddDatabaseOptions): OracleDatabaseResourcePromise { + return new OracleDatabaseResourcePromise(this._promise.then(obj => obj.addDatabase(name, options))); + } + + /** Adds a persistent data volume to the Oracle server resource. */ + withDataVolume(options?: WithDataVolumeOptions): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Mounts a host directory as the Oracle data directory. */ + withDataBindMount(source: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withDataBindMount(source))); + } + + /** Copies initialization files into the Oracle container. */ + withInitFiles(source: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withInitFiles(source))); + } + + /** Mounts a host directory as the Oracle DB setup directory. */ + withDbSetupBindMount(source: string): OracleDatabaseServerResourcePromise { + return new OracleDatabaseServerResourcePromise(this._promise.then(obj => obj.withDbSetupBindMount(source))); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Oracle/Aspire.Hosting.ApplicationModel.OracleDatabaseResource', (handle, client) => new OracleDatabaseResource(handle as OracleDatabaseResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Oracle/Aspire.Hosting.ApplicationModel.OracleDatabaseServerResource', (handle, client) => new OracleDatabaseServerResource(handle as OracleDatabaseServerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..cb50adcaa0d --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/apphost.ts @@ -0,0 +1,68 @@ +// Aspire TypeScript AppHost - Oracle Integration Validation +// Validates all [AspireExport] methods for Aspire.Hosting.Oracle + +import { createBuilder, ContainerLifetime } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// ---- addOracle: factory method with defaults ---- +const oracle = await builder.addOracle("oracledb"); + +// ---- addOracle: factory method with custom password and port ---- +const customPassword = await builder.addParameter("oracle-password", { secret: true }); +const oracle2 = await builder.addOracle("oracledb2", { password: customPassword, port: 1522 }); + +// ---- addDatabase: child resource with default databaseName ---- +const db = await oracle.addDatabase("mydb"); + +// ---- addDatabase: child resource with explicit databaseName ---- +const db2 = await oracle.addDatabase("inventory", { databaseName: "inventorydb" }); + +// ---- withDataVolume: data persistence (default name) ---- +await oracle.withDataVolume(); + +// ---- withDataVolume: data persistence (custom name) ---- +await oracle2.withDataVolume({ name: "oracle-data" }); + +// ---- withDataBindMount: bind mount for data ---- +await oracle2.withDataBindMount("./oracle-data"); + +// ---- withInitFiles: initialization scripts ---- +await oracle2.withInitFiles("./init-scripts"); + +// ---- withDbSetupBindMount: DB setup directory ---- +await oracle2.withDbSetupBindMount("./setup-scripts"); + +// ---- withReference: connection string reference (from core) ---- +const otherOracle = await builder.addOracle("other-oracle"); +const otherDb = await otherOracle.addDatabase("otherdb"); +await oracle.withReference(otherDb); + +// ---- withReference: with connection name option ---- +await oracle.withReference(otherDb, { connectionName: "secondary-db" }); + +// ---- withServiceReference: service discovery reference (from core) ---- +await oracle.withServiceReference(otherOracle); + +// ---- Fluent chaining: multiple methods chained ---- +const oracle3 = await builder.addOracle("oracledb3") + .withLifetime(ContainerLifetime.Persistent) + .withDataVolume({ name: "oracle3-data" }); + +await oracle3.addDatabase("chaineddb"); + +// ---- Property access on OracleDatabaseServerResource ---- +const _endpoint = await oracle.primaryEndpoint.get(); +const _host = await oracle.host.get(); +const _port = await oracle.port.get(); +const _userNameRef = await oracle.userNameReference.get(); +const _uri = await oracle.uriExpression.get(); +const _jdbc = await oracle.jdbcConnectionString.get(); + +// ---- Property access on OracleDatabaseResource ---- +const _dbName: string = await db.databaseName.get(); +const _dbUri = await db.uriExpression.get(); +const _dbJdbc = await db.jdbcConnectionString.get(); +const _dbParent = await db.parent.get(); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Oracle/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..b8f31b7f378 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Qdrant": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..e8bfafad6f2 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +98BC354B0DC55F4D19F751036068386535C90C0A8F0647F2C48D2AC90029ABC0 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..53dbfcd983c --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5491 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to QdrantServerResource */ +type QdrantServerResourceHandle = Handle<'Aspire.Hosting.Qdrant/Aspire.Hosting.ApplicationModel.QdrantServerResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface AddQdrantOptions { + apiKey?: ParameterResource; + grpcPort?: number; + httpPort?: number; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithDataVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Exports AddQdrant for polyglot app hosts. */ + /** @internal */ + async _addQdrantInternal(name: string, apiKey?: ParameterResource, grpcPort?: number, httpPort?: number): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (apiKey !== undefined) rpcArgs.apiKey = apiKey; + if (grpcPort !== undefined) rpcArgs.grpcPort = grpcPort; + if (httpPort !== undefined) rpcArgs.httpPort = httpPort; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Qdrant/addQdrant', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + addQdrant(name: string, options?: AddQdrantOptions): QdrantServerResourcePromise { + const apiKey = options?.apiKey; + const grpcPort = options?.grpcPort; + const httpPort = options?.httpPort; + return new QdrantServerResourcePromise(this._addQdrantInternal(name, apiKey, grpcPort, httpPort)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Exports AddQdrant for polyglot app hosts. */ + addQdrant(name: string, options?: AddQdrantOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.addQdrant(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// QdrantServerResource +// ============================================================================ + +export class QdrantServerResource extends ResourceBuilderBase { + constructor(handle: QdrantServerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): QdrantServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new QdrantServerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): QdrantServerResourcePromise { + const tag = options?.tag; + return new QdrantServerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): QdrantServerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new QdrantServerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): QdrantServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new QdrantServerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): QdrantServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new QdrantServerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): QdrantServerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new QdrantServerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): QdrantServerResourcePromise { + const displayText = options?.displayText; + return new QdrantServerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): QdrantServerResourcePromise { + const displayText = options?.displayText; + return new QdrantServerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): QdrantServerResourcePromise { + const exitCode = options?.exitCode; + return new QdrantServerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): QdrantServerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new QdrantServerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): QdrantServerResourcePromise { + const commandOptions = options?.commandOptions; + return new QdrantServerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): QdrantServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new QdrantServerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Qdrant/withDataVolume', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Exports WithDataVolume for polyglot app hosts. */ + withDataVolume(options?: WithDataVolumeOptions): QdrantServerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new QdrantServerResourcePromise(this._withDataVolumeInternal(name, isReadOnly)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Qdrant/withDataBindMount', + rpcArgs + ); + return new QdrantServerResource(result, this._client); + } + + /** Exports WithDataBindMount for polyglot app hosts. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): QdrantServerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new QdrantServerResourcePromise(this._withDataBindMountInternal(source, isReadOnly)); + } + +} + +/** + * Thenable wrapper for QdrantServerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class QdrantServerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: QdrantServerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Exports WithDataVolume for polyglot app hosts. */ + withDataVolume(options?: WithDataVolumeOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Exports WithDataBindMount for polyglot app hosts. */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): QdrantServerResourcePromise { + return new QdrantServerResourcePromise(this._promise.then(obj => obj.withDataBindMount(source, options))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Qdrant/Aspire.Hosting.ApplicationModel.QdrantServerResource', (handle, client) => new QdrantServerResource(handle as QdrantServerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..c64815aa41e --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/apphost.ts @@ -0,0 +1,6 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); +const qdrant = await builder.addQdrant('qdrant'); +await qdrant.withDataVolume({ name: 'qdrant-data' }).withDataBindMount('.', { isReadOnly: true }); +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Qdrant/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..2f5e7bc6fc9 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Seq": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..2c9fdf6f0be --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +1EC3B24A2350CB2FC0EC2A902C6B8CEC6496F4EF9290DF9B353851756FC0655D \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..9b38e232a47 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5485 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to SeqResource */ +type SeqResourceHandle = Handle<'Aspire.Hosting.Seq/Aspire.Hosting.ApplicationModel.SeqResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface AddSeqOptions { + port?: number; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithDataVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a Seq server container resource */ + /** @internal */ + async _addSeqInternal(name: string, adminPassword: ParameterResource, port?: number): Promise { + const rpcArgs: Record = { builder: this._handle, name, adminPassword }; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Seq/addSeq', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + addSeq(name: string, adminPassword: ParameterResource, options?: AddSeqOptions): SeqResourcePromise { + const port = options?.port; + return new SeqResourcePromise(this._addSeqInternal(name, adminPassword, port)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a Seq server container resource */ + addSeq(name: string, adminPassword: ParameterResource, options?: AddSeqOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.addSeq(name, adminPassword, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// SeqResource +// ============================================================================ + +export class SeqResource extends ResourceBuilderBase { + constructor(handle: SeqResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): SeqResourcePromise { + const isReadOnly = options?.isReadOnly; + return new SeqResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): SeqResourcePromise { + return new SeqResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): SeqResourcePromise { + return new SeqResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): SeqResourcePromise { + return new SeqResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): SeqResourcePromise { + const tag = options?.tag; + return new SeqResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): SeqResourcePromise { + return new SeqResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): SeqResourcePromise { + return new SeqResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): SeqResourcePromise { + return new SeqResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): SeqResourcePromise { + return new SeqResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): SeqResourcePromise { + return new SeqResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): SeqResourcePromise { + return new SeqResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): SeqResourcePromise { + return new SeqResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): SeqResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new SeqResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): SeqResourcePromise { + return new SeqResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): SeqResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new SeqResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): SeqResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new SeqResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): SeqResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new SeqResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): SeqResourcePromise { + return new SeqResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): SeqResourcePromise { + return new SeqResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): SeqResourcePromise { + const displayText = options?.displayText; + return new SeqResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): SeqResourcePromise { + const displayText = options?.displayText; + return new SeqResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): SeqResourcePromise { + return new SeqResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): SeqResourcePromise { + return new SeqResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): SeqResourcePromise { + const exitCode = options?.exitCode; + return new SeqResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): SeqResourcePromise { + return new SeqResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): SeqResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new SeqResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): SeqResourcePromise { + const commandOptions = options?.commandOptions; + return new SeqResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): SeqResourcePromise { + return new SeqResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): SeqResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new SeqResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Seq/withDataVolume', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a data volume for Seq */ + withDataVolume(options?: WithDataVolumeOptions): SeqResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new SeqResourcePromise(this._withDataVolumeInternal(name, isReadOnly)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Seq/withDataBindMount', + rpcArgs + ); + return new SeqResource(result, this._client); + } + + /** Adds a data bind mount for Seq */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): SeqResourcePromise { + const isReadOnly = options?.isReadOnly; + return new SeqResourcePromise(this._withDataBindMountInternal(source, isReadOnly)); + } + +} + +/** + * Thenable wrapper for SeqResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class SeqResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: SeqResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds a data volume for Seq */ + withDataVolume(options?: WithDataVolumeOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Adds a data bind mount for Seq */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): SeqResourcePromise { + return new SeqResourcePromise(this._promise.then(obj => obj.withDataBindMount(source, options))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Seq/Aspire.Hosting.ApplicationModel.SeqResource', (handle, client) => new SeqResource(handle as SeqResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..d13ded7ac2b --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/apphost.ts @@ -0,0 +1,12 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const adminPassword = await builder.addParameter("seq-admin-password", { secret: true }); +const seq = await builder.addSeq("seq", adminPassword, { port: 5341 }); + +await seq.withDataVolume(); +await seq.withDataVolume({ name: "seq-data", isReadOnly: false }); +await seq.withDataBindMount("./seq-data", { isReadOnly: true }); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Seq/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..e32a5a3fb47 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Valkey": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..01b65cfe95f --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +EDFBEC38EE7F0770429C21F0F2E7DB9AB092A5214A8C6ECD16CCD7A2C7C961AC \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..ac6921aa5a7 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5517 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to ValkeyResource */ +type ValkeyResourceHandle = Handle<'Aspire.Hosting.Valkey/Aspire.Hosting.ApplicationModel.ValkeyResource'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface AddValkeyOptions { + port?: number; + password?: ParameterResource; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDataBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithDataVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithPersistenceOptions { + interval?: number; + keysChangedThreshold?: number; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a Valkey container resource */ + /** @internal */ + async _addValkeyInternal(name: string, port?: number, password?: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (port !== undefined) rpcArgs.port = port; + if (password !== undefined) rpcArgs.password = password; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Valkey/addValkey', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + addValkey(name: string, options?: AddValkeyOptions): ValkeyResourcePromise { + const port = options?.port; + const password = options?.password; + return new ValkeyResourcePromise(this._addValkeyInternal(name, port, password)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a Valkey container resource */ + addValkey(name: string, options?: AddValkeyOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.addValkey(name, options))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ValkeyResource +// ============================================================================ + +export class ValkeyResource extends ResourceBuilderBase { + constructor(handle: ValkeyResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ValkeyResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ValkeyResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ValkeyResourcePromise { + const tag = options?.tag; + return new ValkeyResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ValkeyResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ValkeyResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ValkeyResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ValkeyResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ValkeyResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ValkeyResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ValkeyResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ValkeyResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ValkeyResourcePromise { + const displayText = options?.displayText; + return new ValkeyResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ValkeyResourcePromise { + const displayText = options?.displayText; + return new ValkeyResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ValkeyResourcePromise { + const exitCode = options?.exitCode; + return new ValkeyResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ValkeyResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ValkeyResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ValkeyResourcePromise { + const commandOptions = options?.commandOptions; + return new ValkeyResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ValkeyResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ValkeyResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withDataVolumeInternal(name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Valkey/withDataVolume', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a data volume for Valkey and enables persistence */ + withDataVolume(options?: WithDataVolumeOptions): ValkeyResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ValkeyResourcePromise(this._withDataVolumeInternal(name, isReadOnly)); + } + + /** @internal */ + private async _withDataBindMountInternal(source: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Valkey/withDataBindMount', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Adds a data bind mount for Valkey and enables persistence */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): ValkeyResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ValkeyResourcePromise(this._withDataBindMountInternal(source, isReadOnly)); + } + + /** @internal */ + private async _withPersistenceInternal(interval?: number, keysChangedThreshold?: number): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (interval !== undefined) rpcArgs.interval = interval; + if (keysChangedThreshold !== undefined) rpcArgs.keysChangedThreshold = keysChangedThreshold; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Valkey/withPersistence', + rpcArgs + ); + return new ValkeyResource(result, this._client); + } + + /** Configures Valkey persistence */ + withPersistence(options?: WithPersistenceOptions): ValkeyResourcePromise { + const interval = options?.interval; + const keysChangedThreshold = options?.keysChangedThreshold; + return new ValkeyResourcePromise(this._withPersistenceInternal(interval, keysChangedThreshold)); + } + +} + +/** + * Thenable wrapper for ValkeyResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ValkeyResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ValkeyResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Adds a data volume for Valkey and enables persistence */ + withDataVolume(options?: WithDataVolumeOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withDataVolume(options))); + } + + /** Adds a data bind mount for Valkey and enables persistence */ + withDataBindMount(source: string, options?: WithDataBindMountOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withDataBindMount(source, options))); + } + + /** Configures Valkey persistence */ + withPersistence(options?: WithPersistenceOptions): ValkeyResourcePromise { + return new ValkeyResourcePromise(this._promise.then(obj => obj.withPersistence(options))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Valkey/Aspire.Hosting.ApplicationModel.ValkeyResource', (handle, client) => new ValkeyResource(handle as ValkeyResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..4ddc8d1bc14 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/apphost.ts @@ -0,0 +1,12 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); +const password = await builder.addParameter('valkey-password', { secret: true }); +const valkey = await builder.addValkey('cache', { port: 6380, password }); + +await valkey + .withDataVolume({ name: 'valkey-data' }) + .withDataBindMount('.', { isReadOnly: true }) + .withPersistence({ interval: 100000000, keysChangedThreshold: 1 }); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Valkey/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..0f16172d959 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Yarp": "" + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..a6791b3910a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +6A4C36EFAE4AA1BC45BD815CD4BA4047EC2213D97B566767BDB697E4E41603B7 \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..674a510cb40 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,6224 @@ +// aspire.ts - Capability-based Aspire SDK +// This SDK uses the ATS (Aspire Type System) capability API. +// Capabilities are endpoints like 'Aspire.Hosting/createBuilder'. +// +// GENERATED CODE - DO NOT EDIT + +import { + AspireClient as AspireClientRpc, + Handle, + MarshalledHandle, + CapabilityError, + registerCallback, + wrapIfHandle, + registerHandleWrapper +} from './transport.js'; + +import { + ResourceBuilderBase, + ReferenceExpression, + refExpr, + AspireDict, + AspireList +} from './base.js'; + +// ============================================================================ +// Handle Type Aliases (Internal - not exported to users) +// ============================================================================ + +/** Handle to IYarpConfigurationBuilder */ +type IYarpConfigurationBuilderHandle = Handle<'Aspire.Hosting.Yarp/Aspire.Hosting.IYarpConfigurationBuilder'>; + +/** Handle to YarpCluster */ +type YarpClusterHandle = Handle<'Aspire.Hosting.Yarp/Aspire.Hosting.Yarp.YarpCluster'>; + +/** Handle to YarpResource */ +type YarpResourceHandle = Handle<'Aspire.Hosting.Yarp/Aspire.Hosting.Yarp.YarpResource'>; + +/** Handle to YarpRoute */ +type YarpRouteHandle = Handle<'Aspire.Hosting.Yarp/Aspire.Hosting.Yarp.YarpRoute'>; + +/** Handle to CommandLineArgsCallbackContext */ +type CommandLineArgsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext'>; + +/** Handle to ContainerResource */ +type ContainerResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource'>; + +/** Handle to EndpointReference */ +type EndpointReferenceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference'>; + +/** Handle to EndpointReferenceExpression */ +type EndpointReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression'>; + +/** Handle to EnvironmentCallbackContext */ +type EnvironmentCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext'>; + +/** Handle to ExecutableResource */ +type ExecutableResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource'>; + +/** Handle to ExecuteCommandContext */ +type ExecuteCommandContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext'>; + +/** Handle to IResource */ +type IResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource'>; + +/** Handle to IResourceWithArgs */ +type IResourceWithArgsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs'>; + +/** Handle to IResourceWithConnectionString */ +type IResourceWithConnectionStringHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString'>; + +/** Handle to IResourceWithEndpoints */ +type IResourceWithEndpointsHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints'>; + +/** Handle to IResourceWithEnvironment */ +type IResourceWithEnvironmentHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment'>; + +/** Handle to IResourceWithWaitSupport */ +type IResourceWithWaitSupportHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport'>; + +/** Handle to ParameterResource */ +type ParameterResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource'>; + +/** Handle to ProjectResource */ +type ProjectResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource'>; + +/** Handle to ReferenceExpression */ +type ReferenceExpressionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression'>; + +/** Handle to ResourceLoggerService */ +type ResourceLoggerServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService'>; + +/** Handle to ResourceNotificationService */ +type ResourceNotificationServiceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService'>; + +/** Handle to ResourceUrlsCallbackContext */ +type ResourceUrlsCallbackContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext'>; + +/** Handle to DistributedApplication */ +type DistributedApplicationHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplication'>; + +/** Handle to DistributedApplicationExecutionContext */ +type DistributedApplicationExecutionContextHandle = Handle<'Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext'>; + +/** Handle to DistributedApplicationEventSubscription */ +type DistributedApplicationEventSubscriptionHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription'>; + +/** Handle to IDistributedApplicationEventing */ +type IDistributedApplicationEventingHandle = Handle<'Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing'>; + +/** Handle to IDistributedApplicationBuilder */ +type IDistributedApplicationBuilderHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder'>; + +/** Handle to IResourceWithContainerFiles */ +type IResourceWithContainerFilesHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithContainerFiles'>; + +/** Handle to IResourceWithServiceDiscovery */ +type IResourceWithServiceDiscoveryHandle = Handle<'Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery'>; + +/** Handle to Dict */ +type DictstringanyHandle = Handle<'Aspire.Hosting/Dict'>; + +/** Handle to List */ +type ListanyHandle = Handle<'Aspire.Hosting/List'>; + +/** Handle to IConfiguration */ +type IConfigurationHandle = Handle<'Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration'>; + +/** Handle to IHostEnvironment */ +type IHostEnvironmentHandle = Handle<'Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment'>; + +/** Handle to ILogger */ +type ILoggerHandle = Handle<'Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger'>; + +/** Handle to string[] */ +type stringArrayHandle = Handle<'string[]'>; + +/** Handle to IServiceProvider */ +type IServiceProviderHandle = Handle<'System.ComponentModel/System.IServiceProvider'>; + +// ============================================================================ +// Enum Types +// ============================================================================ + +/** Enum type for ContainerLifetime */ +export enum ContainerLifetime { + Session = "Session", + Persistent = "Persistent", +} + +/** Enum type for DistributedApplicationOperation */ +export enum DistributedApplicationOperation { + Run = "Run", + Publish = "Publish", +} + +/** Enum type for EndpointProperty */ +export enum EndpointProperty { + Url = "Url", + Host = "Host", + IPV4Host = "IPV4Host", + Port = "Port", + Scheme = "Scheme", + TargetPort = "TargetPort", + HostAndPort = "HostAndPort", +} + +/** Enum type for ForwardedTransformActions */ +export enum ForwardedTransformActions { + Off = "Off", + Set = "Set", + Append = "Append", + Remove = "Remove", +} + +/** Enum type for IconVariant */ +export enum IconVariant { + Regular = "Regular", + Filled = "Filled", +} + +/** Enum type for ImagePullPolicy */ +export enum ImagePullPolicy { + Default = "Default", + Always = "Always", + Missing = "Missing", + Never = "Never", +} + +/** Enum type for NodeFormat */ +export enum NodeFormat { + None = "None", + Random = "Random", + RandomAndPort = "RandomAndPort", + RandomAndRandomPort = "RandomAndRandomPort", + Unknown = "Unknown", + UnknownAndPort = "UnknownAndPort", + UnknownAndRandomPort = "UnknownAndRandomPort", + Ip = "Ip", + IpAndPort = "IpAndPort", + IpAndRandomPort = "IpAndRandomPort", +} + +/** Enum type for ProtocolType */ +export enum ProtocolType { + IP = "IP", + IPv6HopByHopOptions = "IPv6HopByHopOptions", + Unspecified = "Unspecified", + Icmp = "Icmp", + Igmp = "Igmp", + Ggp = "Ggp", + IPv4 = "IPv4", + Tcp = "Tcp", + Pup = "Pup", + Udp = "Udp", + Idp = "Idp", + IPv6 = "IPv6", + IPv6RoutingHeader = "IPv6RoutingHeader", + IPv6FragmentHeader = "IPv6FragmentHeader", + IPSecEncapsulatingSecurityPayload = "IPSecEncapsulatingSecurityPayload", + IPSecAuthenticationHeader = "IPSecAuthenticationHeader", + IcmpV6 = "IcmpV6", + IPv6NoNextHeader = "IPv6NoNextHeader", + IPv6DestinationOptions = "IPv6DestinationOptions", + ND = "ND", + Raw = "Raw", + Ipx = "Ipx", + Spx = "Spx", + SpxII = "SpxII", + Unknown = "Unknown", +} + +/** Enum type for ResponseCondition */ +export enum ResponseCondition { + Always = "Always", + Success = "Success", + Failure = "Failure", +} + +/** Enum type for UrlDisplayLocation */ +export enum UrlDisplayLocation { + SummaryAndDetails = "SummaryAndDetails", + DetailsOnly = "DetailsOnly", +} + +// ============================================================================ +// DTO Interfaces +// ============================================================================ + +/** DTO interface for CommandOptions */ +export interface CommandOptions { + description?: string; + parameter?: any; + confirmationMessage?: string; + iconName?: string; + iconVariant?: IconVariant; + isHighlighted?: boolean; + updateState?: any; +} + +/** DTO interface for CreateBuilderOptions */ +export interface CreateBuilderOptions { + args?: string[]; + projectDirectory?: string; + appHostFilePath?: string; + containerRegistryOverride?: string; + disableDashboard?: boolean; + dashboardApplicationName?: string; + allowUnsecuredTransport?: boolean; + enableResourceLogging?: boolean; +} + +/** DTO interface for ExecuteCommandResult */ +export interface ExecuteCommandResult { + success?: boolean; + canceled?: boolean; + errorMessage?: string; +} + +/** DTO interface for ResourceEventDto */ +export interface ResourceEventDto { + resourceName?: string; + resourceId?: string; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; +} + +/** DTO interface for ResourceUrlAnnotation */ +export interface ResourceUrlAnnotation { + url?: string; + displayText?: string; + endpoint?: EndpointReferenceHandle; + displayLocation?: UrlDisplayLocation; +} + +// ============================================================================ +// Options Interfaces +// ============================================================================ + +export interface AddConnectionStringOptions { + environmentVariableName?: string; +} + +export interface AddParameterOptions { + secret?: boolean; +} + +export interface GetValueAsyncOptions { + cancellationToken?: AbortSignal; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDescriptionOptions { + enableMarkdown?: boolean; +} + +export interface WithEndpointOptions { + port?: number; + targetPort?: number; + scheme?: string; + name?: string; + env?: string; + isProxied?: boolean; + isExternal?: boolean; + protocol?: ProtocolType; +} + +export interface WithHostHttpsPortOptions { + port?: number; +} + +export interface WithHostPortOptions { + port?: number; +} + +export interface WithHttpEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithHttpHealthCheckOptions { + path?: string; + statusCode?: number; + endpointName?: string; +} + +export interface WithHttpsEndpointOptions { + port?: number; + targetPort?: number; + name?: string; + env?: string; + isProxied?: boolean; +} + +export interface WithImageOptions { + tag?: string; +} + +export interface WithReferenceOptions { + connectionName?: string; + optional?: boolean; +} + +export interface WithTransformCopyRequestHeadersOptions { + copy?: boolean; +} + +export interface WithTransformCopyResponseHeadersOptions { + copy?: boolean; +} + +export interface WithTransformCopyResponseTrailersOptions { + copy?: boolean; +} + +export interface WithTransformForwardedOptions { + useHost?: boolean; + useProto?: boolean; + forFormat?: NodeFormat; + byFormat?: NodeFormat; + action?: ForwardedTransformActions; +} + +export interface WithTransformQueryRouteValueOptions { + append?: boolean; +} + +export interface WithTransformQueryValueOptions { + append?: boolean; +} + +export interface WithTransformRequestHeaderOptions { + append?: boolean; +} + +export interface WithTransformRequestHeaderRouteValueOptions { + append?: boolean; +} + +export interface WithTransformResponseHeaderOptions { + append?: boolean; + condition?: ResponseCondition; +} + +export interface WithTransformResponseHeaderRemoveOptions { + condition?: ResponseCondition; +} + +export interface WithTransformResponseTrailerOptions { + append?: boolean; + condition?: ResponseCondition; +} + +export interface WithTransformResponseTrailerRemoveOptions { + condition?: ResponseCondition; +} + +export interface WithTransformUseOriginalHostHeaderOptions { + useOriginal?: boolean; +} + +export interface WithTransformXForwardedOptions { + headerPrefix?: string; + xDefault?: ForwardedTransformActions; + xFor?: ForwardedTransformActions; + xHost?: ForwardedTransformActions; + xProto?: ForwardedTransformActions; + xPrefix?: ForwardedTransformActions; +} + +export interface WithUrlExpressionOptions { + displayText?: string; +} + +export interface WithUrlOptions { + displayText?: string; +} + +export interface WithVolumeOptions { + name?: string; + isReadOnly?: boolean; +} + +// ============================================================================ +// CommandLineArgsCallbackContext +// ============================================================================ + +/** + * Type class for CommandLineArgsCallbackContext. + */ +export class CommandLineArgsCallbackContext { + constructor(private _handle: CommandLineArgsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Args property */ + private _args?: AspireList; + get args(): AspireList { + if (!this._args) { + this._args = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args', + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.args' + ); + } + return this._args; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/CommandLineArgsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// DistributedApplication +// ============================================================================ + +/** + * Type class for DistributedApplication. + */ +export class DistributedApplication { + constructor(private _handle: DistributedApplicationHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Runs the distributed application */ + /** @internal */ + async _runInternal(cancellationToken?: AbortSignal): Promise { + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + await this._client.invokeCapability( + 'Aspire.Hosting/run', + rpcArgs + ); + return this; + } + + run(options?: RunOptions): DistributedApplicationPromise { + const cancellationToken = options?.cancellationToken; + return new DistributedApplicationPromise(this._runInternal(cancellationToken)); + } + +} + +/** + * Thenable wrapper for DistributedApplication that enables fluent chaining. + */ +export class DistributedApplicationPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplication) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Runs the distributed application */ + run(options?: RunOptions): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.run(options))); + } + +} + +// ============================================================================ +// DistributedApplicationExecutionContext +// ============================================================================ + +/** + * Type class for DistributedApplicationExecutionContext. + */ +export class DistributedApplicationExecutionContext { + constructor(private _handle: DistributedApplicationExecutionContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the PublisherName property */ + publisherName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.publisherName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.setPublisherName', + { context: this._handle, value } + ); + } + }; + + /** Gets the Operation property */ + operation = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.operation', + { context: this._handle } + ); + }, + }; + + /** Gets the IsPublishMode property */ + isPublishMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isPublishMode', + { context: this._handle } + ); + }, + }; + + /** Gets the IsRunMode property */ + isRunMode = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/DistributedApplicationExecutionContext.isRunMode', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EndpointReference +// ============================================================================ + +/** + * Type class for EndpointReference. + */ +export class EndpointReference { + constructor(private _handle: EndpointReferenceHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EndpointName property */ + endpointName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.endpointName', + { context: this._handle } + ); + }, + }; + + /** Gets the ErrorMessage property */ + errorMessage = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.errorMessage', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.setErrorMessage', + { context: this._handle, value } + ); + } + }; + + /** Gets the IsAllocated property */ + isAllocated = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isAllocated', + { context: this._handle } + ); + }, + }; + + /** Gets the Exists property */ + exists = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.exists', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttp property */ + isHttp = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttp', + { context: this._handle } + ); + }, + }; + + /** Gets the IsHttps property */ + isHttps = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.isHttps', + { context: this._handle } + ); + }, + }; + + /** Gets the Port property */ + port = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.port', + { context: this._handle } + ); + }, + }; + + /** Gets the TargetPort property */ + targetPort = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.targetPort', + { context: this._handle } + ); + }, + }; + + /** Gets the Host property */ + host = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.host', + { context: this._handle } + ); + }, + }; + + /** Gets the Scheme property */ + scheme = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.scheme', + { context: this._handle } + ); + }, + }; + + /** Gets the Url property */ + url = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReference.url', + { context: this._handle } + ); + }, + }; + + /** Gets the URL of the endpoint asynchronously */ + async getValueAsync(options?: GetValueAsyncOptions): Promise { + const cancellationToken = options?.cancellationToken; + const rpcArgs: Record = { context: this._handle }; + if (cancellationToken !== undefined) rpcArgs.cancellationToken = cancellationToken; + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/getValueAsync', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for EndpointReference that enables fluent chaining. + */ +export class EndpointReferencePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: EndpointReference) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Gets the URL of the endpoint asynchronously */ + getValueAsync(options?: GetValueAsyncOptions): Promise { + return this._promise.then(obj => obj.getValueAsync(options)); + } + +} + +// ============================================================================ +// EndpointReferenceExpression +// ============================================================================ + +/** + * Type class for EndpointReferenceExpression. + */ +export class EndpointReferenceExpression { + constructor(private _handle: EndpointReferenceExpressionHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Endpoint property */ + endpoint = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.endpoint', + { context: this._handle } + ); + return new EndpointReference(handle, this._client); + }, + }; + + /** Gets the Property property */ + property = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.property', + { context: this._handle } + ); + }, + }; + + /** Gets the ValueExpression property */ + valueExpression = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EndpointReferenceExpression.valueExpression', + { context: this._handle } + ); + }, + }; + +} + +// ============================================================================ +// EnvironmentCallbackContext +// ============================================================================ + +/** + * Type class for EnvironmentCallbackContext. + */ +export class EnvironmentCallbackContext { + constructor(private _handle: EnvironmentCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the EnvironmentVariables property */ + private _environmentVariables?: AspireDict; + get environmentVariables(): AspireDict { + if (!this._environmentVariables) { + this._environmentVariables = new AspireDict( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables', + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables' + ); + } + return this._environmentVariables; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// ExecuteCommandContext +// ============================================================================ + +/** + * Type class for ExecuteCommandContext. + */ +export class ExecuteCommandContext { + constructor(private _handle: ExecuteCommandContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the ResourceName property */ + resourceName = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName', + { context: this._handle } + ); + }, + set: async (value: string): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName', + { context: this._handle, value } + ); + } + }; + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken', + { context: this._handle } + ); + }, + set: async (value: AbortSignal): Promise => { + await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken', + { context: this._handle, value } + ); + } + }; + +} + +// ============================================================================ +// ResourceUrlsCallbackContext +// ============================================================================ + +/** + * Type class for ResourceUrlsCallbackContext. + */ +export class ResourceUrlsCallbackContext { + constructor(private _handle: ResourceUrlsCallbackContextHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the Urls property */ + private _urls?: AspireList; + get urls(): AspireList { + if (!this._urls) { + this._urls = new AspireList( + this._handle, + this._client, + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls', + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.urls' + ); + } + return this._urls; + } + + /** Gets the CancellationToken property */ + cancellationToken = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.cancellationToken', + { context: this._handle } + ); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ResourceUrlsCallbackContext.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + +} + +// ============================================================================ +// YarpRoute +// ============================================================================ + +/** + * Type class for YarpRoute. + */ +export class YarpRoute { + constructor(private _handle: YarpRouteHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Adds the transform which will add X-Forwarded-* headers. */ + /** @internal */ + async _withTransformXForwardedInternal(headerPrefix?: string, xDefault?: ForwardedTransformActions, xFor?: ForwardedTransformActions, xHost?: ForwardedTransformActions, xProto?: ForwardedTransformActions, xPrefix?: ForwardedTransformActions): Promise { + const rpcArgs: Record = { route: this._handle }; + if (headerPrefix !== undefined) rpcArgs.headerPrefix = headerPrefix; + if (xDefault !== undefined) rpcArgs.xDefault = xDefault; + if (xFor !== undefined) rpcArgs.xFor = xFor; + if (xHost !== undefined) rpcArgs.xHost = xHost; + if (xProto !== undefined) rpcArgs.xProto = xProto; + if (xPrefix !== undefined) rpcArgs.xPrefix = xPrefix; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformXForwarded', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformXForwarded(options?: WithTransformXForwardedOptions): YarpRoutePromise { + const headerPrefix = options?.headerPrefix; + const xDefault = options?.xDefault; + const xFor = options?.xFor; + const xHost = options?.xHost; + const xProto = options?.xProto; + const xPrefix = options?.xPrefix; + return new YarpRoutePromise(this._withTransformXForwardedInternal(headerPrefix, xDefault, xFor, xHost, xProto, xPrefix)); + } + + /** Adds the transform which will add the Forwarded header as defined by [RFC 7239](https://tools.ietf.org/html/rfc7239). */ + /** @internal */ + async _withTransformForwardedInternal(useHost?: boolean, useProto?: boolean, forFormat?: NodeFormat, byFormat?: NodeFormat, action?: ForwardedTransformActions): Promise { + const rpcArgs: Record = { route: this._handle }; + if (useHost !== undefined) rpcArgs.useHost = useHost; + if (useProto !== undefined) rpcArgs.useProto = useProto; + if (forFormat !== undefined) rpcArgs.forFormat = forFormat; + if (byFormat !== undefined) rpcArgs.byFormat = byFormat; + if (action !== undefined) rpcArgs.action = action; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformForwarded', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformForwarded(options?: WithTransformForwardedOptions): YarpRoutePromise { + const useHost = options?.useHost; + const useProto = options?.useProto; + const forFormat = options?.forFormat; + const byFormat = options?.byFormat; + const action = options?.action; + return new YarpRoutePromise(this._withTransformForwardedInternal(useHost, useProto, forFormat, byFormat, action)); + } + + /** Adds the transform which will set the given header with the Base64 encoded client certificate. */ + /** @internal */ + async _withTransformClientCertHeaderInternal(headerName: string): Promise { + const rpcArgs: Record = { route: this._handle, headerName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformClientCertHeader', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformClientCertHeader(headerName: string): YarpRoutePromise { + return new YarpRoutePromise(this._withTransformClientCertHeaderInternal(headerName)); + } + + /** Adds the transform that will replace the HTTP method if it matches. */ + /** @internal */ + async _withTransformHttpMethodChangeInternal(fromHttpMethod: string, toHttpMethod: string): Promise { + const rpcArgs: Record = { route: this._handle, fromHttpMethod, toHttpMethod }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformHttpMethodChange', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformHttpMethodChange(fromHttpMethod: string, toHttpMethod: string): YarpRoutePromise { + return new YarpRoutePromise(this._withTransformHttpMethodChangeInternal(fromHttpMethod, toHttpMethod)); + } + + /** Adds the transform that will append or set the query parameter from the given value. */ + /** @internal */ + async _withTransformQueryValueInternal(queryKey: string, value: string, append?: boolean): Promise { + const rpcArgs: Record = { route: this._handle, queryKey, value }; + if (append !== undefined) rpcArgs.append = append; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformQueryValue', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformQueryValue(queryKey: string, value: string, options?: WithTransformQueryValueOptions): YarpRoutePromise { + const append = options?.append; + return new YarpRoutePromise(this._withTransformQueryValueInternal(queryKey, value, append)); + } + + /** Adds the transform that will append or set the query parameter from a route value. */ + /** @internal */ + async _withTransformQueryRouteValueInternal(queryKey: string, routeValueKey: string, append?: boolean): Promise { + const rpcArgs: Record = { route: this._handle, queryKey, routeValueKey }; + if (append !== undefined) rpcArgs.append = append; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformQueryRouteValue', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformQueryRouteValue(queryKey: string, routeValueKey: string, options?: WithTransformQueryRouteValueOptions): YarpRoutePromise { + const append = options?.append; + return new YarpRoutePromise(this._withTransformQueryRouteValueInternal(queryKey, routeValueKey, append)); + } + + /** Adds the transform that will remove the given query key. */ + /** @internal */ + async _withTransformQueryRemoveKeyInternal(queryKey: string): Promise { + const rpcArgs: Record = { route: this._handle, queryKey }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformQueryRemoveKey', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformQueryRemoveKey(queryKey: string): YarpRoutePromise { + return new YarpRoutePromise(this._withTransformQueryRemoveKeyInternal(queryKey)); + } + + /** Adds the transform which will enable or suppress copying request headers to the proxy request. */ + /** @internal */ + async _withTransformCopyRequestHeadersInternal(copy?: boolean): Promise { + const rpcArgs: Record = { route: this._handle }; + if (copy !== undefined) rpcArgs.copy = copy; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformCopyRequestHeaders', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformCopyRequestHeaders(options?: WithTransformCopyRequestHeadersOptions): YarpRoutePromise { + const copy = options?.copy; + return new YarpRoutePromise(this._withTransformCopyRequestHeadersInternal(copy)); + } + + /** Adds the transform which will copy the incoming request Host header to the proxy request. */ + /** @internal */ + async _withTransformUseOriginalHostHeaderInternal(useOriginal?: boolean): Promise { + const rpcArgs: Record = { route: this._handle }; + if (useOriginal !== undefined) rpcArgs.useOriginal = useOriginal; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformUseOriginalHostHeader', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformUseOriginalHostHeader(options?: WithTransformUseOriginalHostHeaderOptions): YarpRoutePromise { + const useOriginal = options?.useOriginal; + return new YarpRoutePromise(this._withTransformUseOriginalHostHeaderInternal(useOriginal)); + } + + /** Adds the transform which will append or set the request header. */ + /** @internal */ + async _withTransformRequestHeaderInternal(headerName: string, value: string, append?: boolean): Promise { + const rpcArgs: Record = { route: this._handle, headerName, value }; + if (append !== undefined) rpcArgs.append = append; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformRequestHeader', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformRequestHeader(headerName: string, value: string, options?: WithTransformRequestHeaderOptions): YarpRoutePromise { + const append = options?.append; + return new YarpRoutePromise(this._withTransformRequestHeaderInternal(headerName, value, append)); + } + + /** Adds the transform which will append or set the request header from a route value. */ + /** @internal */ + async _withTransformRequestHeaderRouteValueInternal(headerName: string, routeValueKey: string, append?: boolean): Promise { + const rpcArgs: Record = { route: this._handle, headerName, routeValueKey }; + if (append !== undefined) rpcArgs.append = append; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformRequestHeaderRouteValue', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformRequestHeaderRouteValue(headerName: string, routeValueKey: string, options?: WithTransformRequestHeaderRouteValueOptions): YarpRoutePromise { + const append = options?.append; + return new YarpRoutePromise(this._withTransformRequestHeaderRouteValueInternal(headerName, routeValueKey, append)); + } + + /** Adds the transform which will remove the request header. */ + /** @internal */ + async _withTransformRequestHeaderRemoveInternal(headerName: string): Promise { + const rpcArgs: Record = { route: this._handle, headerName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformRequestHeaderRemove', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformRequestHeaderRemove(headerName: string): YarpRoutePromise { + return new YarpRoutePromise(this._withTransformRequestHeaderRemoveInternal(headerName)); + } + + /** Adds the transform which will only copy the allowed request headers. Other transforms */ + /** @internal */ + async _withTransformRequestHeadersAllowedInternal(allowedHeaders: string[]): Promise { + const rpcArgs: Record = { route: this._handle, allowedHeaders }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformRequestHeadersAllowed', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformRequestHeadersAllowed(allowedHeaders: string[]): YarpRoutePromise { + return new YarpRoutePromise(this._withTransformRequestHeadersAllowedInternal(allowedHeaders)); + } + + /** Adds the transform which will enable or suppress copying response headers to the client response. */ + /** @internal */ + async _withTransformCopyResponseHeadersInternal(copy?: boolean): Promise { + const rpcArgs: Record = { route: this._handle }; + if (copy !== undefined) rpcArgs.copy = copy; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformCopyResponseHeaders', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformCopyResponseHeaders(options?: WithTransformCopyResponseHeadersOptions): YarpRoutePromise { + const copy = options?.copy; + return new YarpRoutePromise(this._withTransformCopyResponseHeadersInternal(copy)); + } + + /** Adds the transform which will enable or suppress copying response trailers to the client response. */ + /** @internal */ + async _withTransformCopyResponseTrailersInternal(copy?: boolean): Promise { + const rpcArgs: Record = { route: this._handle }; + if (copy !== undefined) rpcArgs.copy = copy; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformCopyResponseTrailers', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformCopyResponseTrailers(options?: WithTransformCopyResponseTrailersOptions): YarpRoutePromise { + const copy = options?.copy; + return new YarpRoutePromise(this._withTransformCopyResponseTrailersInternal(copy)); + } + + /** Adds the transform which will append or set the response header. */ + /** @internal */ + async _withTransformResponseHeaderInternal(headerName: string, value: string, append?: boolean, condition?: ResponseCondition): Promise { + const rpcArgs: Record = { route: this._handle, headerName, value }; + if (append !== undefined) rpcArgs.append = append; + if (condition !== undefined) rpcArgs.condition = condition; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformResponseHeader', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformResponseHeader(headerName: string, value: string, options?: WithTransformResponseHeaderOptions): YarpRoutePromise { + const append = options?.append; + const condition = options?.condition; + return new YarpRoutePromise(this._withTransformResponseHeaderInternal(headerName, value, append, condition)); + } + + /** Adds the transform which will remove the response header. */ + /** @internal */ + async _withTransformResponseHeaderRemoveInternal(headerName: string, condition?: ResponseCondition): Promise { + const rpcArgs: Record = { route: this._handle, headerName }; + if (condition !== undefined) rpcArgs.condition = condition; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformResponseHeaderRemove', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformResponseHeaderRemove(headerName: string, options?: WithTransformResponseHeaderRemoveOptions): YarpRoutePromise { + const condition = options?.condition; + return new YarpRoutePromise(this._withTransformResponseHeaderRemoveInternal(headerName, condition)); + } + + /** Adds the transform which will only copy the allowed response headers. Other transforms */ + /** @internal */ + async _withTransformResponseHeadersAllowedInternal(allowedHeaders: string[]): Promise { + const rpcArgs: Record = { route: this._handle, allowedHeaders }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformResponseHeadersAllowed', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformResponseHeadersAllowed(allowedHeaders: string[]): YarpRoutePromise { + return new YarpRoutePromise(this._withTransformResponseHeadersAllowedInternal(allowedHeaders)); + } + + /** Adds the transform which will append or set the response trailer. */ + /** @internal */ + async _withTransformResponseTrailerInternal(headerName: string, value: string, append?: boolean, condition?: ResponseCondition): Promise { + const rpcArgs: Record = { route: this._handle, headerName, value }; + if (append !== undefined) rpcArgs.append = append; + if (condition !== undefined) rpcArgs.condition = condition; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformResponseTrailer', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformResponseTrailer(headerName: string, value: string, options?: WithTransformResponseTrailerOptions): YarpRoutePromise { + const append = options?.append; + const condition = options?.condition; + return new YarpRoutePromise(this._withTransformResponseTrailerInternal(headerName, value, append, condition)); + } + + /** Adds the transform which will remove the response trailer. */ + /** @internal */ + async _withTransformResponseTrailerRemoveInternal(headerName: string, condition?: ResponseCondition): Promise { + const rpcArgs: Record = { route: this._handle, headerName }; + if (condition !== undefined) rpcArgs.condition = condition; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformResponseTrailerRemove', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformResponseTrailerRemove(headerName: string, options?: WithTransformResponseTrailerRemoveOptions): YarpRoutePromise { + const condition = options?.condition; + return new YarpRoutePromise(this._withTransformResponseTrailerRemoveInternal(headerName, condition)); + } + + /** Adds the transform which will only copy the allowed response trailers. Other transforms */ + /** @internal */ + async _withTransformResponseTrailersAllowedInternal(allowedHeaders: string[]): Promise { + const rpcArgs: Record = { route: this._handle, allowedHeaders }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withTransformResponseTrailersAllowed', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + withTransformResponseTrailersAllowed(allowedHeaders: string[]): YarpRoutePromise { + return new YarpRoutePromise(this._withTransformResponseTrailersAllowedInternal(allowedHeaders)); + } + +} + +/** + * Thenable wrapper for YarpRoute that enables fluent chaining. + */ +export class YarpRoutePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: YarpRoute) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds the transform which will add X-Forwarded-* headers. */ + withTransformXForwarded(options?: WithTransformXForwardedOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformXForwarded(options))); + } + + /** Adds the transform which will add the Forwarded header as defined by [RFC 7239](https://tools.ietf.org/html/rfc7239). */ + withTransformForwarded(options?: WithTransformForwardedOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformForwarded(options))); + } + + /** Adds the transform which will set the given header with the Base64 encoded client certificate. */ + withTransformClientCertHeader(headerName: string): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformClientCertHeader(headerName))); + } + + /** Adds the transform that will replace the HTTP method if it matches. */ + withTransformHttpMethodChange(fromHttpMethod: string, toHttpMethod: string): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformHttpMethodChange(fromHttpMethod, toHttpMethod))); + } + + /** Adds the transform that will append or set the query parameter from the given value. */ + withTransformQueryValue(queryKey: string, value: string, options?: WithTransformQueryValueOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformQueryValue(queryKey, value, options))); + } + + /** Adds the transform that will append or set the query parameter from a route value. */ + withTransformQueryRouteValue(queryKey: string, routeValueKey: string, options?: WithTransformQueryRouteValueOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformQueryRouteValue(queryKey, routeValueKey, options))); + } + + /** Adds the transform that will remove the given query key. */ + withTransformQueryRemoveKey(queryKey: string): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformQueryRemoveKey(queryKey))); + } + + /** Adds the transform which will enable or suppress copying request headers to the proxy request. */ + withTransformCopyRequestHeaders(options?: WithTransformCopyRequestHeadersOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformCopyRequestHeaders(options))); + } + + /** Adds the transform which will copy the incoming request Host header to the proxy request. */ + withTransformUseOriginalHostHeader(options?: WithTransformUseOriginalHostHeaderOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformUseOriginalHostHeader(options))); + } + + /** Adds the transform which will append or set the request header. */ + withTransformRequestHeader(headerName: string, value: string, options?: WithTransformRequestHeaderOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformRequestHeader(headerName, value, options))); + } + + /** Adds the transform which will append or set the request header from a route value. */ + withTransformRequestHeaderRouteValue(headerName: string, routeValueKey: string, options?: WithTransformRequestHeaderRouteValueOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformRequestHeaderRouteValue(headerName, routeValueKey, options))); + } + + /** Adds the transform which will remove the request header. */ + withTransformRequestHeaderRemove(headerName: string): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformRequestHeaderRemove(headerName))); + } + + /** Adds the transform which will only copy the allowed request headers. Other transforms */ + withTransformRequestHeadersAllowed(allowedHeaders: string[]): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformRequestHeadersAllowed(allowedHeaders))); + } + + /** Adds the transform which will enable or suppress copying response headers to the client response. */ + withTransformCopyResponseHeaders(options?: WithTransformCopyResponseHeadersOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformCopyResponseHeaders(options))); + } + + /** Adds the transform which will enable or suppress copying response trailers to the client response. */ + withTransformCopyResponseTrailers(options?: WithTransformCopyResponseTrailersOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformCopyResponseTrailers(options))); + } + + /** Adds the transform which will append or set the response header. */ + withTransformResponseHeader(headerName: string, value: string, options?: WithTransformResponseHeaderOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformResponseHeader(headerName, value, options))); + } + + /** Adds the transform which will remove the response header. */ + withTransformResponseHeaderRemove(headerName: string, options?: WithTransformResponseHeaderRemoveOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformResponseHeaderRemove(headerName, options))); + } + + /** Adds the transform which will only copy the allowed response headers. Other transforms */ + withTransformResponseHeadersAllowed(allowedHeaders: string[]): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformResponseHeadersAllowed(allowedHeaders))); + } + + /** Adds the transform which will append or set the response trailer. */ + withTransformResponseTrailer(headerName: string, value: string, options?: WithTransformResponseTrailerOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformResponseTrailer(headerName, value, options))); + } + + /** Adds the transform which will remove the response trailer. */ + withTransformResponseTrailerRemove(headerName: string, options?: WithTransformResponseTrailerRemoveOptions): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformResponseTrailerRemove(headerName, options))); + } + + /** Adds the transform which will only copy the allowed response trailers. Other transforms */ + withTransformResponseTrailersAllowed(allowedHeaders: string[]): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.withTransformResponseTrailersAllowed(allowedHeaders))); + } + +} + +// ============================================================================ +// DistributedApplicationBuilder +// ============================================================================ + +/** + * Type class for DistributedApplicationBuilder. + */ +export class DistributedApplicationBuilder { + constructor(private _handle: IDistributedApplicationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Gets the AppHostDirectory property */ + appHostDirectory = { + get: async (): Promise => { + return await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.appHostDirectory', + { context: this._handle } + ); + }, + }; + + /** Gets the Eventing property */ + eventing = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.eventing', + { context: this._handle } + ); + return new DistributedApplicationEventing(handle, this._client); + }, + }; + + /** Gets the ExecutionContext property */ + executionContext = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting/IDistributedApplicationBuilder.executionContext', + { context: this._handle } + ); + return new DistributedApplicationExecutionContext(handle, this._client); + }, + }; + + /** Builds the distributed application */ + /** @internal */ + async _buildInternal(): Promise { + const rpcArgs: Record = { context: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/build', + rpcArgs + ); + return new DistributedApplication(result, this._client); + } + + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._buildInternal()); + } + + /** Adds a container resource */ + /** @internal */ + async _addContainerInternal(name: string, image: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, image }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._addContainerInternal(name, image)); + } + + /** Adds an executable resource */ + /** @internal */ + async _addExecutableInternal(name: string, command: string, workingDirectory: string, args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, name, command, workingDirectory, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addExecutable', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._addExecutableInternal(name, command, workingDirectory, args)); + } + + /** Adds a parameter resource */ + /** @internal */ + async _addParameterInternal(name: string, secret?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (secret !== undefined) rpcArgs.secret = secret; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addParameter', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + const secret = options?.secret; + return new ParameterResourcePromise(this._addParameterInternal(name, secret)); + } + + /** Adds a connection string resource */ + /** @internal */ + async _addConnectionStringInternal(name: string, environmentVariableName?: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + if (environmentVariableName !== undefined) rpcArgs.environmentVariableName = environmentVariableName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addConnectionString', + rpcArgs + ); + return new ResourceWithConnectionString(result, this._client); + } + + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + const environmentVariableName = options?.environmentVariableName; + return new ResourceWithConnectionStringPromise(this._addConnectionStringInternal(name, environmentVariableName)); + } + + /** Adds a .NET project resource */ + /** @internal */ + async _addProjectInternal(name: string, projectPath: string, launchProfileName: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, projectPath, launchProfileName }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/addProject', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._addProjectInternal(name, projectPath, launchProfileName)); + } + + /** Adds a YARP container to the application model. */ + /** @internal */ + async _addYarpInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/addYarp', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + addYarp(name: string): YarpResourcePromise { + return new YarpResourcePromise(this._addYarpInternal(name)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationBuilder that enables fluent chaining. + */ +export class DistributedApplicationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Builds the distributed application */ + build(): DistributedApplicationPromise { + return new DistributedApplicationPromise(this._promise.then(obj => obj.build())); + } + + /** Adds a container resource */ + addContainer(name: string, image: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.addContainer(name, image))); + } + + /** Adds an executable resource */ + addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.addExecutable(name, command, workingDirectory, args))); + } + + /** Adds a parameter resource */ + addParameter(name: string, options?: AddParameterOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.addParameter(name, options))); + } + + /** Adds a connection string resource */ + addConnectionString(name: string, options?: AddConnectionStringOptions): ResourceWithConnectionStringPromise { + return new ResourceWithConnectionStringPromise(this._promise.then(obj => obj.addConnectionString(name, options))); + } + + /** Adds a .NET project resource */ + addProject(name: string, projectPath: string, launchProfileName: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.addProject(name, projectPath, launchProfileName))); + } + + /** Adds a YARP container to the application model. */ + addYarp(name: string): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.addYarp(name))); + } + +} + +// ============================================================================ +// DistributedApplicationEventing +// ============================================================================ + +/** + * Type class for DistributedApplicationEventing. + */ +export class DistributedApplicationEventing { + constructor(private _handle: IDistributedApplicationEventingHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the Unsubscribe method */ + /** @internal */ + async _unsubscribeInternal(subscription: DistributedApplicationEventSubscriptionHandle): Promise { + const rpcArgs: Record = { context: this._handle, subscription }; + await this._client.invokeCapability( + 'Aspire.Hosting.Eventing/IDistributedApplicationEventing.unsubscribe', + rpcArgs + ); + return this; + } + + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._unsubscribeInternal(subscription)); + } + +} + +/** + * Thenable wrapper for DistributedApplicationEventing that enables fluent chaining. + */ +export class DistributedApplicationEventingPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: DistributedApplicationEventing) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the Unsubscribe method */ + unsubscribe(subscription: DistributedApplicationEventSubscriptionHandle): DistributedApplicationEventingPromise { + return new DistributedApplicationEventingPromise(this._promise.then(obj => obj.unsubscribe(subscription))); + } + +} + +// ============================================================================ +// YarpConfigurationBuilder +// ============================================================================ + +/** + * Type class for YarpConfigurationBuilder. + */ +export class YarpConfigurationBuilder { + constructor(private _handle: IYarpConfigurationBuilderHandle, private _client: AspireClientRpc) {} + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { return this._handle.toJSON(); } + + /** Invokes the AddRoute method */ + /** @internal */ + async _addRouteInternal(path: string, cluster: YarpClusterHandle): Promise { + const rpcArgs: Record = { context: this._handle, path, cluster }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/IYarpConfigurationBuilder.addRoute', + rpcArgs + ); + return new YarpRoute(result, this._client); + } + + addRoute(path: string, cluster: YarpClusterHandle): YarpRoutePromise { + return new YarpRoutePromise(this._addRouteInternal(path, cluster)); + } + + /** Invokes the AddCluster method */ + async addCluster(endpoint: EndpointReference): Promise { + const rpcArgs: Record = { context: this._handle, endpoint }; + return await this._client.invokeCapability( + 'Aspire.Hosting/IYarpConfigurationBuilder.addCluster', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for YarpConfigurationBuilder that enables fluent chaining. + */ +export class YarpConfigurationBuilderPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: YarpConfigurationBuilder) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Invokes the AddRoute method */ + addRoute(path: string, cluster: YarpClusterHandle): YarpRoutePromise { + return new YarpRoutePromise(this._promise.then(obj => obj.addRoute(path, cluster))); + } + + /** Invokes the AddCluster method */ + addCluster(endpoint: EndpointReference): Promise { + return this._promise.then(obj => obj.addCluster(endpoint)); + } + +} + +// ============================================================================ +// ContainerResource +// ============================================================================ + +export class ContainerResource extends ResourceBuilderBase { + constructor(handle: ContainerResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ContainerResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ContainerResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ContainerResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + const displayText = options?.displayText; + return new ContainerResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + const exitCode = options?.exitCode; + return new ContainerResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ContainerResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + const commandOptions = options?.commandOptions; + return new ContainerResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ContainerResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ContainerResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ContainerResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ExecutableResource +// ============================================================================ + +export class ExecutableResource extends ResourceBuilderBase { + constructor(handle: ExecutableResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ExecutableResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ExecutableResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ExecutableResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + const displayText = options?.displayText; + return new ExecutableResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + const exitCode = options?.exitCode; + return new ExecutableResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ExecutableResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + const commandOptions = options?.commandOptions; + return new ExecutableResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ExecutableResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ExecutableResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ExecutableResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ParameterResource +// ============================================================================ + +export class ParameterResource extends ResourceBuilderBase { + constructor(handle: ParameterResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withDescriptionInternal(description: string, enableMarkdown?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, description }; + if (enableMarkdown !== undefined) rpcArgs.enableMarkdown = enableMarkdown; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDescription', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + const enableMarkdown = options?.enableMarkdown; + return new ParameterResourcePromise(this._withDescriptionInternal(description, enableMarkdown)); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + const displayText = options?.displayText; + return new ParameterResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + const commandOptions = options?.commandOptions; + return new ParameterResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ParameterResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ParameterResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ParameterResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ParameterResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets a parameter description */ + withDescription(description: string, options?: WithDescriptionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withDescription(description, options))); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ParameterResourcePromise { + return new ParameterResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ProjectResource +// ============================================================================ + +export class ProjectResource extends ResourceBuilderBase { + constructor(handle: ProjectResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ProjectResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ProjectResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ProjectResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + const displayText = options?.displayText; + return new ProjectResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + const exitCode = options?.exitCode; + return new ProjectResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ProjectResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + const commandOptions = options?.commandOptions; + return new ProjectResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for ProjectResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ProjectResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ProjectResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// YarpResource +// ============================================================================ + +export class YarpResource extends ResourceBuilderBase { + constructor(handle: YarpResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withBindMountInternal(source: string, target: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): YarpResourcePromise { + const isReadOnly = options?.isReadOnly; + return new YarpResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): YarpResourcePromise { + return new YarpResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): YarpResourcePromise { + return new YarpResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): YarpResourcePromise { + return new YarpResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): YarpResourcePromise { + const tag = options?.tag; + return new YarpResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): YarpResourcePromise { + return new YarpResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): YarpResourcePromise { + return new YarpResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): YarpResourcePromise { + return new YarpResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): YarpResourcePromise { + return new YarpResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): YarpResourcePromise { + return new YarpResourcePromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): YarpResourcePromise { + return new YarpResourcePromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): YarpResourcePromise { + return new YarpResourcePromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withArgsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): YarpResourcePromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new YarpResourcePromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._withServiceReferenceInternal(source)); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): YarpResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new YarpResourcePromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): YarpResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new YarpResourcePromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): YarpResourcePromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new YarpResourcePromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): YarpResourcePromise { + return new YarpResourcePromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): YarpResourcePromise { + return new YarpResourcePromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): YarpResourcePromise { + const displayText = options?.displayText; + return new YarpResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): YarpResourcePromise { + const displayText = options?.displayText; + return new YarpResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): YarpResourcePromise { + return new YarpResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): YarpResourcePromise { + const exitCode = options?.exitCode; + return new YarpResourcePromise(this._waitForCompletionInternal(dependency, exitCode)); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): YarpResourcePromise { + return new YarpResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): YarpResourcePromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new YarpResourcePromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): YarpResourcePromise { + const commandOptions = options?.commandOptions; + return new YarpResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** @internal */ + private async _withVolumeInternal(target: string, name?: string, isReadOnly?: boolean): Promise { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): YarpResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new YarpResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + + /** @internal */ + private async _withConfigurationInternal(configurationBuilder: (obj: YarpConfigurationBuilder) => Promise): Promise { + const configurationBuilderId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as IYarpConfigurationBuilderHandle; + const obj = new YarpConfigurationBuilder(objHandle, this._client); + await configurationBuilder(obj); + }); + const rpcArgs: Record = { builder: this._handle, configurationBuilder: configurationBuilderId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withConfiguration', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Configure the YARP resource. */ + withConfiguration(configurationBuilder: (obj: YarpConfigurationBuilder) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._withConfigurationInternal(configurationBuilder)); + } + + /** @internal */ + private async _withHostPortInternal(port?: number): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withHostPort', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Configures the host port that the YARP resource is exposed on instead of using randomly assigned port. */ + withHostPort(options?: WithHostPortOptions): YarpResourcePromise { + const port = options?.port; + return new YarpResourcePromise(this._withHostPortInternal(port)); + } + + /** @internal */ + private async _withHostHttpsPortInternal(port?: number): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/withHostHttpsPort', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** Configures the host HTTPS port that the YARP resource is exposed on instead of using randomly assigned port. */ + withHostHttpsPort(options?: WithHostHttpsPortOptions): YarpResourcePromise { + const port = options?.port; + return new YarpResourcePromise(this._withHostHttpsPortInternal(port)); + } + + /** @internal */ + private async _publishWithStaticFilesInternal(resourceWithFiles: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, resourceWithFiles }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Yarp/publishWithStaticFiles', + rpcArgs + ); + return new YarpResource(result, this._client); + } + + /** In publish mode, generates a Dockerfile that copies static files from the specified resource into /app/wwwroot. */ + publishWithStaticFiles(resourceWithFiles: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._publishWithStaticFilesInternal(resourceWithFiles)); + } + +} + +/** + * Thenable wrapper for YarpResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class YarpResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: YarpResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Sets the container name */ + withContainerName(name: string): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds arguments */ + withArgs(args: string[]): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withServiceReference(source))); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Configure the YARP resource. */ + withConfiguration(configurationBuilder: (obj: YarpConfigurationBuilder) => Promise): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withConfiguration(configurationBuilder))); + } + + /** Configures the host port that the YARP resource is exposed on instead of using randomly assigned port. */ + withHostPort(options?: WithHostPortOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withHostPort(options))); + } + + /** Configures the host HTTPS port that the YARP resource is exposed on instead of using randomly assigned port. */ + withHostHttpsPort(options?: WithHostHttpsPortOptions): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.withHostHttpsPort(options))); + } + + /** In publish mode, generates a Dockerfile that copies static files from the specified resource into /app/wwwroot. */ + publishWithStaticFiles(resourceWithFiles: ResourceBuilderBase): YarpResourcePromise { + return new YarpResourcePromise(this._promise.then(obj => obj.publishWithStaticFiles(resourceWithFiles))); + } + +} + +// ============================================================================ +// Resource +// ============================================================================ + +export class Resource extends ResourceBuilderBase { + constructor(handle: IResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withUrlsCallbackInternal(callback: (obj: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ResourceUrlsCallbackContextHandle; + const obj = new ResourceUrlsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallback', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackInternal(callback)); + } + + /** @internal */ + private async _withUrlsCallbackAsyncInternal(callback: (arg: ResourceUrlsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ResourceUrlsCallbackContextHandle; + const arg = new ResourceUrlsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlsCallbackAsync', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlsCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withUrlInternal(url: string, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrl', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlExpressionInternal(url: ReferenceExpression, displayText?: string): Promise { + const rpcArgs: Record = { builder: this._handle, url }; + if (displayText !== undefined) rpcArgs.displayText = displayText; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlExpression', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + const displayText = options?.displayText; + return new ResourcePromise(this._withUrlExpressionInternal(url, displayText)); + } + + /** @internal */ + private async _withUrlForEndpointInternal(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const obj = wrapIfHandle(objData) as ResourceUrlAnnotation; + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpoint', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._withUrlForEndpointInternal(endpointName, callback)); + } + + /** @internal */ + private async _withExplicitStartInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExplicitStart', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._withExplicitStartInternal()); + } + + /** @internal */ + private async _withHealthCheckInternal(key: string): Promise { + const rpcArgs: Record = { builder: this._handle, key }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHealthCheck', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._withHealthCheckInternal(key)); + } + + /** @internal */ + private async _withCommandInternal(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, commandOptions?: CommandOptions): Promise { + const executeCommandId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as ExecuteCommandContextHandle; + const arg = new ExecuteCommandContext(argHandle, this._client); + return await executeCommand(arg); + }); + const rpcArgs: Record = { builder: this._handle, name, displayName, executeCommand: executeCommandId }; + if (commandOptions !== undefined) rpcArgs.commandOptions = commandOptions; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withCommand', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + const commandOptions = options?.commandOptions; + return new ResourcePromise(this._withCommandInternal(name, displayName, executeCommand, commandOptions)); + } + + /** @internal */ + private async _withParentRelationshipInternal(parent: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, parent }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withParentRelationship', + rpcArgs + ); + return new Resource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._withParentRelationshipInternal(parent)); + } + + /** Gets the resource name */ + async getResourceName(): Promise { + const rpcArgs: Record = { resource: this._handle }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getResourceName', + rpcArgs + ); + } + +} + +/** + * Thenable wrapper for Resource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: Resource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): ResourcePromise { + return new ResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + +} + +// ============================================================================ +// ResourceWithArgs +// ============================================================================ + +export class ResourceWithArgs extends ResourceBuilderBase { + constructor(handle: IResourceWithArgsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgs', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsInternal(args)); + } + + /** @internal */ + private async _withArgsCallbackInternal(callback: (obj: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as CommandLineArgsCallbackContextHandle; + const obj = new CommandLineArgsCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallback', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackInternal(callback)); + } + + /** @internal */ + private async _withArgsCallbackAsyncInternal(callback: (arg: CommandLineArgsCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as CommandLineArgsCallbackContextHandle; + const arg = new CommandLineArgsCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withArgsCallbackAsync', + rpcArgs + ); + return new ResourceWithArgs(result, this._client); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._withArgsCallbackAsyncInternal(callback)); + } + +} + +/** + * Thenable wrapper for ResourceWithArgs that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithArgsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithArgs) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds arguments */ + withArgs(args: string[]): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgs(args))); + } + + /** Sets command-line arguments via callback */ + withArgsCallback(callback: (obj: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallback(callback))); + } + + /** Sets command-line arguments via async callback */ + withArgsCallbackAsync(callback: (arg: CommandLineArgsCallbackContext) => Promise): ResourceWithArgsPromise { + return new ResourceWithArgsPromise(this._promise.then(obj => obj.withArgsCallbackAsync(callback))); + } + +} + +// ============================================================================ +// ResourceWithConnectionString +// ============================================================================ + +export class ResourceWithConnectionString extends ResourceBuilderBase { + constructor(handle: IResourceWithConnectionStringHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithConnectionString that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithConnectionStringPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithConnectionString) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithContainerFiles +// ============================================================================ + +export class ResourceWithContainerFiles extends ResourceBuilderBase { + constructor(handle: IResourceWithContainerFilesHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithContainerFiles that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithContainerFilesPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithContainerFiles) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithEndpoints +// ============================================================================ + +export class ResourceWithEndpoints extends ResourceBuilderBase { + constructor(handle: IResourceWithEndpointsHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEndpointInternal(port?: number, targetPort?: number, scheme?: string, name?: string, env?: string, isProxied?: boolean, isExternal?: boolean, protocol?: ProtocolType): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (scheme !== undefined) rpcArgs.scheme = scheme; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + if (isExternal !== undefined) rpcArgs.isExternal = isExternal; + if (protocol !== undefined) rpcArgs.protocol = protocol; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const scheme = options?.scheme; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + const isExternal = options?.isExternal; + const protocol = options?.protocol; + return new ResourceWithEndpointsPromise(this._withEndpointInternal(port, targetPort, scheme, name, env, isProxied, isExternal, protocol)); + } + + /** @internal */ + private async _withHttpEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withHttpsEndpointInternal(port?: number, targetPort?: number, name?: string, env?: string, isProxied?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (port !== undefined) rpcArgs.port = port; + if (targetPort !== undefined) rpcArgs.targetPort = targetPort; + if (name !== undefined) rpcArgs.name = name; + if (env !== undefined) rpcArgs.env = env; + if (isProxied !== undefined) rpcArgs.isProxied = isProxied; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpsEndpoint', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + const port = options?.port; + const targetPort = options?.targetPort; + const name = options?.name; + const env = options?.env; + const isProxied = options?.isProxied; + return new ResourceWithEndpointsPromise(this._withHttpsEndpointInternal(port, targetPort, name, env, isProxied)); + } + + /** @internal */ + private async _withExternalHttpEndpointsInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExternalHttpEndpoints', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withExternalHttpEndpointsInternal()); + } + + /** Gets an endpoint reference */ + async getEndpoint(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + return await this._client.invokeCapability( + 'Aspire.Hosting/getEndpoint', + rpcArgs + ); + } + + /** @internal */ + private async _asHttp2ServiceInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/asHttp2Service', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._asHttp2ServiceInternal()); + } + + /** @internal */ + private async _withUrlForEndpointFactoryInternal(endpointName: string, callback: (arg: EndpointReference) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EndpointReferenceHandle; + const arg = new EndpointReference(argHandle, this._client); + return await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, endpointName, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withUrlForEndpointFactory', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._withUrlForEndpointFactoryInternal(endpointName, callback)); + } + + /** @internal */ + private async _withHttpHealthCheckInternal(path?: string, statusCode?: number, endpointName?: string): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (path !== undefined) rpcArgs.path = path; + if (statusCode !== undefined) rpcArgs.statusCode = statusCode; + if (endpointName !== undefined) rpcArgs.endpointName = endpointName; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withHttpHealthCheck', + rpcArgs + ); + return new ResourceWithEndpoints(result, this._client); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + const path = options?.path; + const statusCode = options?.statusCode; + const endpointName = options?.endpointName; + return new ResourceWithEndpointsPromise(this._withHttpHealthCheckInternal(path, statusCode, endpointName)); + } + +} + +/** + * Thenable wrapper for ResourceWithEndpoints that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEndpointsPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEndpoints) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Adds a network endpoint */ + withEndpoint(options?: WithEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withEndpoint(options))); + } + + /** Adds an HTTP endpoint */ + withHttpEndpoint(options?: WithHttpEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpEndpoint(options))); + } + + /** Adds an HTTPS endpoint */ + withHttpsEndpoint(options?: WithHttpsEndpointOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpsEndpoint(options))); + } + + /** Makes HTTP endpoints externally accessible */ + withExternalHttpEndpoints(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withExternalHttpEndpoints())); + } + + /** Gets an endpoint reference */ + getEndpoint(name: string): Promise { + return this._promise.then(obj => obj.getEndpoint(name)); + } + + /** Configures resource for HTTP/2 */ + asHttp2Service(): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.asHttp2Service())); + } + + /** Adds a URL for a specific endpoint via factory callback */ + withUrlForEndpointFactory(endpointName: string, callback: (arg: EndpointReference) => Promise): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withUrlForEndpointFactory(endpointName, callback))); + } + + /** Adds an HTTP health check */ + withHttpHealthCheck(options?: WithHttpHealthCheckOptions): ResourceWithEndpointsPromise { + return new ResourceWithEndpointsPromise(this._promise.then(obj => obj.withHttpHealthCheck(options))); + } + +} + +// ============================================================================ +// ResourceWithEnvironment +// ============================================================================ + +export class ResourceWithEnvironment extends ResourceBuilderBase { + constructor(handle: IResourceWithEnvironmentHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _withEnvironmentInternal(name: string, value: string): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironment', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentExpressionInternal(name: string, value: ReferenceExpression): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentExpression', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentExpressionInternal(name, value)); + } + + /** @internal */ + private async _withEnvironmentCallbackInternal(callback: (obj: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as EnvironmentCallbackContextHandle; + const obj = new EnvironmentCallbackContext(objHandle, this._client); + await callback(obj); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallback', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackInternal(callback)); + } + + /** @internal */ + private async _withEnvironmentCallbackAsyncInternal(callback: (arg: EnvironmentCallbackContext) => Promise): Promise { + const callbackId = registerCallback(async (argData: unknown) => { + const argHandle = wrapIfHandle(argData) as EnvironmentCallbackContextHandle; + const arg = new EnvironmentCallbackContext(argHandle, this._client); + await callback(arg); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEnvironmentCallbackAsync', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withEnvironmentCallbackAsyncInternal(callback)); + } + + /** @internal */ + private async _withReferenceInternal(source: ResourceBuilderBase, connectionName?: string, optional?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + if (connectionName !== undefined) rpcArgs.connectionName = connectionName; + if (optional !== undefined) rpcArgs.optional = optional; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + const connectionName = options?.connectionName; + const optional = options?.optional; + return new ResourceWithEnvironmentPromise(this._withReferenceInternal(source, connectionName, optional)); + } + + /** @internal */ + private async _withServiceReferenceInternal(source: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, source }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withServiceReference', + rpcArgs + ); + return new ResourceWithEnvironment(result, this._client); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._withServiceReferenceInternal(source)); + } + +} + +/** + * Thenable wrapper for ResourceWithEnvironment that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithEnvironmentPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithEnvironment) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Sets an environment variable */ + withEnvironment(name: string, value: string): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironment(name, value))); + } + + /** Adds an environment variable with a reference expression */ + withEnvironmentExpression(name: string, value: ReferenceExpression): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentExpression(name, value))); + } + + /** Sets environment variables via callback */ + withEnvironmentCallback(callback: (obj: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallback(callback))); + } + + /** Sets environment variables via async callback */ + withEnvironmentCallbackAsync(callback: (arg: EnvironmentCallbackContext) => Promise): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withEnvironmentCallbackAsync(callback))); + } + + /** Adds a reference to another resource */ + withReference(source: ResourceBuilderBase, options?: WithReferenceOptions): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withReference(source, options))); + } + + /** Adds a service discovery reference to another resource */ + withServiceReference(source: ResourceBuilderBase): ResourceWithEnvironmentPromise { + return new ResourceWithEnvironmentPromise(this._promise.then(obj => obj.withServiceReference(source))); + } + +} + +// ============================================================================ +// ResourceWithServiceDiscovery +// ============================================================================ + +export class ResourceWithServiceDiscovery extends ResourceBuilderBase { + constructor(handle: IResourceWithServiceDiscoveryHandle, client: AspireClientRpc) { + super(handle, client); + } + +} + +/** + * Thenable wrapper for ResourceWithServiceDiscovery that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithServiceDiscoveryPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithServiceDiscovery) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + +} + +// ============================================================================ +// ResourceWithWaitSupport +// ============================================================================ + +export class ResourceWithWaitSupport extends ResourceBuilderBase { + constructor(handle: IResourceWithWaitSupportHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _waitForInternal(dependency: ResourceBuilderBase): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitFor', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._waitForInternal(dependency)); + } + + /** @internal */ + private async _waitForCompletionInternal(dependency: ResourceBuilderBase, exitCode?: number): Promise { + const rpcArgs: Record = { builder: this._handle, dependency }; + if (exitCode !== undefined) rpcArgs.exitCode = exitCode; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/waitForCompletion', + rpcArgs + ); + return new ResourceWithWaitSupport(result, this._client); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + const exitCode = options?.exitCode; + return new ResourceWithWaitSupportPromise(this._waitForCompletionInternal(dependency, exitCode)); + } + +} + +/** + * Thenable wrapper for ResourceWithWaitSupport that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ResourceWithWaitSupportPromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ResourceWithWaitSupport) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Waits for another resource to be ready */ + waitFor(dependency: ResourceBuilderBase): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitFor(dependency))); + } + + /** Waits for resource completion */ + waitForCompletion(dependency: ResourceBuilderBase, options?: WaitForCompletionOptions): ResourceWithWaitSupportPromise { + return new ResourceWithWaitSupportPromise(this._promise.then(obj => obj.waitForCompletion(dependency, options))); + } + +} + +// ============================================================================ +// Connection Helper +// ============================================================================ + +/** + * Creates and connects to the Aspire AppHost. + * Reads connection info from environment variables set by `aspire run`. + */ +export async function connect(): Promise { + const socketPath = process.env.REMOTE_APP_HOST_SOCKET_PATH; + if (!socketPath) { + throw new Error( + 'REMOTE_APP_HOST_SOCKET_PATH environment variable not set. ' + + 'Run this application using `aspire run`.' + ); + } + + const client = new AspireClientRpc(socketPath); + await client.connect(); + + // Exit the process if the server connection is lost + client.onDisconnect(() => { + console.error('Connection to AppHost lost. Exiting...'); + process.exit(1); + }); + + return client; +} + +/** + * Creates a new distributed application builder. + * This is the entry point for building Aspire applications. + * + * @param options - Optional configuration options for the builder + * @returns A DistributedApplicationBuilder instance + * + * @example + * const builder = await createBuilder(); + * builder.addRedis("cache"); + * builder.addContainer("api", "mcr.microsoft.com/dotnet/samples:aspnetapp"); + * const app = await builder.build(); + * await app.run(); + */ +export async function createBuilder(options?: CreateBuilderOptions): Promise { + const client = await connect(); + + // Default args, projectDirectory, and appHostFilePath if not provided + // ASPIRE_APPHOST_FILEPATH is set by the CLI for consistent socket hash computation + const effectiveOptions: CreateBuilderOptions = { + ...options, + args: options?.args ?? process.argv.slice(2), + projectDirectory: options?.projectDirectory ?? process.env.ASPIRE_PROJECT_DIRECTORY ?? process.cwd(), + appHostFilePath: options?.appHostFilePath ?? process.env.ASPIRE_APPHOST_FILEPATH + }; + + const handle = await client.invokeCapability( + 'Aspire.Hosting/createBuilderWithOptions', + { options: effectiveOptions } + ); + return new DistributedApplicationBuilder(handle, client); +} + +// Re-export commonly used types +export { Handle, CapabilityError, registerCallback } from './transport.js'; +export { refExpr, ReferenceExpression } from './base.js'; + +// ============================================================================ +// Global Error Handling +// ============================================================================ + +/** + * Set up global error handlers to ensure the process exits properly on errors. + * Node.js doesn't exit on unhandled rejections by default, so we need to handle them. + */ +process.on('unhandledRejection', (reason: unknown) => { + const error = reason instanceof Error ? reason : new Error(String(reason)); + + if (reason instanceof CapabilityError) { + console.error(`\n❌ Capability Error: ${error.message}`); + console.error(` Code: ${(reason as CapabilityError).code}`); + if ((reason as CapabilityError).capability) { + console.error(` Capability: ${(reason as CapabilityError).capability}`); + } + } else { + console.error(`\n❌ Unhandled Error: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + } + + process.exit(1); +}); + +process.on('uncaughtException', (error: Error) => { + console.error(`\n❌ Uncaught Exception: ${error.message}`); + if (error.stack) { + console.error(error.stack); + } + process.exit(1); +}); + +// ============================================================================ +// Handle Wrapper Registrations +// ============================================================================ + +// Register wrapper factories for typed handle wrapping in callbacks +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext', (handle, client) => new CommandLineArgsCallbackContext(handle as CommandLineArgsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplication', (handle, client) => new DistributedApplication(handle as DistributedApplicationHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext', (handle, client) => new DistributedApplicationExecutionContext(handle as DistributedApplicationExecutionContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference', (handle, client) => new EndpointReference(handle as EndpointReferenceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression', (handle, client) => new EndpointReferenceExpression(handle as EndpointReferenceExpressionHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext', (handle, client) => new EnvironmentCallbackContext(handle as EnvironmentCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext', (handle, client) => new ExecuteCommandContext(handle as ExecuteCommandContextHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext', (handle, client) => new ResourceUrlsCallbackContext(handle as ResourceUrlsCallbackContextHandle, client)); +registerHandleWrapper('Aspire.Hosting.Yarp/Aspire.Hosting.Yarp.YarpRoute', (handle, client) => new YarpRoute(handle as YarpRouteHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder', (handle, client) => new DistributedApplicationBuilder(handle as IDistributedApplicationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing', (handle, client) => new DistributedApplicationEventing(handle as IDistributedApplicationEventingHandle, client)); +registerHandleWrapper('Aspire.Hosting.Yarp/Aspire.Hosting.IYarpConfigurationBuilder', (handle, client) => new YarpConfigurationBuilder(handle as IYarpConfigurationBuilderHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource', (handle, client) => new ContainerResource(handle as ContainerResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource', (handle, client) => new ExecutableResource(handle as ExecutableResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource', (handle, client) => new ParameterResource(handle as ParameterResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource', (handle, client) => new ProjectResource(handle as ProjectResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Yarp/Aspire.Hosting.Yarp.YarpResource', (handle, client) => new YarpResource(handle as YarpResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource', (handle, client) => new Resource(handle as IResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs', (handle, client) => new ResourceWithArgs(handle as IResourceWithArgsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString', (handle, client) => new ResourceWithConnectionString(handle as IResourceWithConnectionStringHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithContainerFiles', (handle, client) => new ResourceWithContainerFiles(handle as IResourceWithContainerFilesHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints', (handle, client) => new ResourceWithEndpoints(handle as IResourceWithEndpointsHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment', (handle, client) => new ResourceWithEnvironment(handle as IResourceWithEnvironmentHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery', (handle, client) => new ResourceWithServiceDiscovery(handle as IResourceWithServiceDiscoveryHandle, client)); +registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport', (handle, client) => new ResourceWithWaitSupport(handle as IResourceWithWaitSupportHandle, client)); + diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/base.ts @@ -0,0 +1,453 @@ +// aspire.ts - Core Aspire types: base classes, ReferenceExpression +import { Handle, AspireClient, MarshalledHandle } from './transport.js'; + +// Re-export transport types for convenience +export { Handle, AspireClient, CapabilityError, registerCallback, unregisterCallback, registerCancellation, unregisterCancellation } from './transport.js'; +export type { MarshalledHandle, AtsError, AtsErrorDetails, CallbackFunction } from './transport.js'; +export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './transport.js'; + +// ============================================================================ +// Reference Expression +// ============================================================================ + +/** + * Represents a reference expression that can be passed to capabilities. + * + * Reference expressions are serialized in the protocol as: + * ```json + * { + * "$expr": { + * "format": "redis://{0}:{1}", + * "valueProviders": [ + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:1" }, + * { "$handle": "Aspire.Hosting.ApplicationModel/EndpointReference:2" } + * ] + * } + * } + * ``` + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export class ReferenceExpression { + private readonly _format: string; + private readonly _valueProviders: unknown[]; + + private constructor(format: string, valueProviders: unknown[]) { + this._format = format; + this._valueProviders = valueProviders; + } + + /** + * Creates a reference expression from a tagged template literal. + * + * @param strings - The template literal string parts + * @param values - The interpolated values (handles to value providers) + * @returns A ReferenceExpression instance + */ + static create(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + // Build the format string with {0}, {1}, etc. placeholders + let format = ''; + for (let i = 0; i < strings.length; i++) { + format += strings[i]; + if (i < values.length) { + format += `{${i}}`; + } + } + + // Extract handles from values + const valueProviders = values.map(extractHandleForExpr); + + return new ReferenceExpression(format, valueProviders); + } + + /** + * Serializes the reference expression for JSON-RPC transport. + * Uses the $expr format recognized by the server. + */ + toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } { + return { + $expr: { + format: this._format, + valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined + } + }; + } + + /** + * String representation for debugging. + */ + toString(): string { + return `ReferenceExpression(${this._format})`; + } +} + +/** + * Extracts a value for use in reference expressions. + * Supports handles (objects) and string literals. + * @internal + */ +function extractHandleForExpr(value: unknown): unknown { + if (value === null || value === undefined) { + throw new Error('Cannot use null or undefined in reference expression'); + } + + // String literals - include directly in the expression + if (typeof value === 'string') { + return value; + } + + // Number literals - convert to string + if (typeof value === 'number') { + return String(value); + } + + // Handle objects - get their JSON representation + if (value instanceof Handle) { + return value.toJSON(); + } + + // Objects with $handle property (already in handle format) + if (typeof value === 'object' && value !== null && '$handle' in value) { + return value; + } + + // Objects with toJSON that returns a handle + if (typeof value === 'object' && value !== null && 'toJSON' in value && typeof value.toJSON === 'function') { + const json = value.toJSON(); + if (json && typeof json === 'object' && '$handle' in json) { + return json; + } + } + + throw new Error( + `Cannot use value of type ${typeof value} in reference expression. ` + + `Expected a Handle, string, or number.` + ); +} + +/** + * Tagged template function for creating reference expressions. + * + * Use this to create dynamic expressions that reference endpoints, parameters, and other + * value providers. The expression is evaluated at runtime by Aspire. + * + * @example + * ```typescript + * const redis = await builder.addRedis("cache"); + * const endpoint = await redis.getEndpoint("tcp"); + * + * // Create a reference expression using the tagged template + * const expr = refExpr`redis://${endpoint}:6379`; + * + * // Use it in an environment variable + * await api.withEnvironment("REDIS_URL", expr); + * ``` + */ +export function refExpr(strings: TemplateStringsArray, ...values: unknown[]): ReferenceExpression { + return ReferenceExpression.create(strings, ...values); +} + +// ============================================================================ +// ResourceBuilderBase +// ============================================================================ + +/** + * Base class for resource builders (e.g., RedisBuilder, ContainerBuilder). + * Provides handle management and JSON serialization. + */ +export class ResourceBuilderBase { + constructor(protected _handle: THandle, protected _client: AspireClient) {} + + toJSON(): MarshalledHandle { return this._handle.toJSON(); } +} + +// ============================================================================ +// AspireList - Mutable List Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET List. + * Provides array-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const items = await resource.getItems(); // Returns AspireList + * const count = await items.count(); + * const first = await items.get(0); + * await items.add(newItem); + * ``` + */ +export class AspireList { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the list handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual list handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual list handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of elements in the list. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.length', { + list: handle + }) as number; + } + + /** + * Gets the element at the specified index. + */ + async get(index: number): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.get', { + list: handle, + index + }) as T; + } + + /** + * Adds an element to the end of the list. + */ + async add(item: T): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.add', { + list: handle, + item + }); + } + + /** + * Removes the element at the specified index. + */ + async removeAt(index: number): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.removeAt', { + list: handle, + index + }); + } + + /** + * Clears all elements from the list. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/List.clear', { + list: handle + }); + } + + /** + * Converts the list to an array (creates a copy). + */ + async toArray(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/List.toArray', { + list: handle + }) as T[]; + } + + toJSON(): MarshalledHandle { + if (this._resolvedHandle) { + return this._resolvedHandle.toJSON(); + } + return this._handleOrContext.toJSON(); + } +} + +// ============================================================================ +// AspireDict - Mutable Dictionary Wrapper +// ============================================================================ + +/** + * Wrapper for a mutable .NET Dictionary. + * Provides object-like methods that invoke capabilities on the underlying collection. + * + * @example + * ```typescript + * const config = await resource.getConfig(); // Returns AspireDict + * const value = await config.get("key"); + * await config.set("key", "value"); + * const hasKey = await config.containsKey("key"); + * ``` + */ +export class AspireDict { + private _resolvedHandle?: Handle; + private _resolvePromise?: Promise; + + constructor( + private readonly _handleOrContext: Handle, + private readonly _client: AspireClient, + private readonly _typeId: string, + private readonly _getterCapabilityId?: string + ) { + // If no getter capability, the handle is already the dictionary handle + if (!_getterCapabilityId) { + this._resolvedHandle = _handleOrContext; + } + } + + /** + * Ensures we have the actual dictionary handle by calling the getter if needed. + */ + private async _ensureHandle(): Promise { + if (this._resolvedHandle) { + return this._resolvedHandle; + } + if (this._resolvePromise) { + return this._resolvePromise; + } + // Call the getter capability to get the actual dictionary handle + this._resolvePromise = (async () => { + const result = await this._client.invokeCapability(this._getterCapabilityId!, { + context: this._handleOrContext + }); + this._resolvedHandle = result as Handle; + return this._resolvedHandle; + })(); + return this._resolvePromise; + } + + /** + * Gets the number of key-value pairs in the dictionary. + */ + async count(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.count', { + dict: handle + }) as number; + } + + /** + * Gets the value associated with the specified key. + * @throws If the key is not found. + */ + async get(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.get', { + dict: handle, + key + }) as V; + } + + /** + * Sets the value for the specified key. + */ + async set(key: K, value: V): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.set', { + dict: handle, + key, + value + }); + } + + /** + * Determines whether the dictionary contains the specified key. + */ + async containsKey(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.has', { + dict: handle, + key + }) as boolean; + } + + /** + * Removes the value with the specified key. + * @returns True if the element was removed; false if the key was not found. + */ + async remove(key: K): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.remove', { + dict: handle, + key + }) as boolean; + } + + /** + * Clears all key-value pairs from the dictionary. + */ + async clear(): Promise { + const handle = await this._ensureHandle(); + await this._client.invokeCapability('Aspire.Hosting/Dict.clear', { + dict: handle + }); + } + + /** + * Gets all keys in the dictionary. + */ + async keys(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.keys', { + dict: handle + }) as K[]; + } + + /** + * Gets all values in the dictionary. + */ + async values(): Promise { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.values', { + dict: handle + }) as V[]; + } + + /** + * Converts the dictionary to a plain object (creates a copy). + * Only works when K is string. + */ + async toObject(): Promise> { + const handle = await this._ensureHandle(); + return await this._client.invokeCapability('Aspire.Hosting/Dict.toObject', { + dict: handle + }) as Record; + } + + async toJSON(): Promise { + const handle = await this._ensureHandle(); + return handle.toJSON(); + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/.modules/transport.ts @@ -0,0 +1,557 @@ +// transport.ts - ATS transport layer: RPC, Handle, errors, callbacks +import * as net from 'net'; +import * as rpc from 'vscode-jsonrpc/node.js'; + +// ============================================================================ +// Base Types +// ============================================================================ + +/** + * Type for callback functions that can be registered and invoked from .NET. + * Internal: receives args and client for handle wrapping. + */ +export type CallbackFunction = (args: unknown, client: AspireClient) => unknown | Promise; + +/** + * Represents a handle to a .NET object in the ATS system. + * Handles are typed references that can be passed between capabilities. + */ +export interface MarshalledHandle { + /** The handle ID (instance number) */ + $handle: string; + /** The ATS type ID */ + $type: string; +} + +/** + * Error details for ATS errors. + */ +export interface AtsErrorDetails { + /** The parameter that caused the error */ + parameter?: string; + /** The expected type or value */ + expected?: string; + /** The actual type or value */ + actual?: string; +} + +/** + * Structured error from ATS capability invocation. + */ +export interface AtsError { + /** Machine-readable error code */ + code: string; + /** Human-readable error message */ + message: string; + /** The capability that failed (if applicable) */ + capability?: string; + /** Additional error details */ + details?: AtsErrorDetails; +} + +/** + * ATS error codes returned by the server. + */ +export const AtsErrorCodes = { + /** Unknown capability ID */ + CapabilityNotFound: 'CAPABILITY_NOT_FOUND', + /** Handle ID doesn't exist or was disposed */ + HandleNotFound: 'HANDLE_NOT_FOUND', + /** Handle type doesn't satisfy capability's type constraint */ + TypeMismatch: 'TYPE_MISMATCH', + /** Missing required argument or wrong type */ + InvalidArgument: 'INVALID_ARGUMENT', + /** Argument value outside valid range */ + ArgumentOutOfRange: 'ARGUMENT_OUT_OF_RANGE', + /** Error occurred during callback invocation */ + CallbackError: 'CALLBACK_ERROR', + /** Unexpected error in capability execution */ + InternalError: 'INTERNAL_ERROR', +} as const; + +/** + * Type guard to check if a value is an ATS error response. + */ +export function isAtsError(value: unknown): value is { $error: AtsError } { + return ( + value !== null && + typeof value === 'object' && + '$error' in value && + typeof (value as { $error: unknown }).$error === 'object' + ); +} + +/** + * Type guard to check if a value is a marshalled handle. + */ +export function isMarshalledHandle(value: unknown): value is MarshalledHandle { + return ( + value !== null && + typeof value === 'object' && + '$handle' in value && + '$type' in value + ); +} + +// ============================================================================ +// Handle +// ============================================================================ + +/** + * A typed handle to a .NET object in the ATS system. + * Handles are opaque references that can be passed to capabilities. + * + * @typeParam T - The ATS type ID (e.g., "Aspire.Hosting/IDistributedApplicationBuilder") + */ +export class Handle { + private readonly _handleId: string; + private readonly _typeId: T; + + constructor(marshalled: MarshalledHandle) { + this._handleId = marshalled.$handle; + this._typeId = marshalled.$type as T; + } + + /** The handle ID (instance number) */ + get $handle(): string { + return this._handleId; + } + + /** The ATS type ID */ + get $type(): T { + return this._typeId; + } + + /** Serialize for JSON-RPC transport */ + toJSON(): MarshalledHandle { + return { + $handle: this._handleId, + $type: this._typeId + }; + } + + /** String representation for debugging */ + toString(): string { + return `Handle<${this._typeId}>(${this._handleId})`; + } +} + +// ============================================================================ +// Handle Wrapper Registry +// ============================================================================ + +/** + * Factory function for creating typed wrapper instances from handles. + */ +export type HandleWrapperFactory = (handle: Handle, client: AspireClient) => unknown; + +/** + * Registry of handle wrapper factories by type ID. + * Generated code registers wrapper classes here so callback handles can be properly typed. + */ +const handleWrapperRegistry = new Map(); + +/** + * Register a wrapper factory for a type ID. + * Called by generated code to register wrapper classes. + */ +export function registerHandleWrapper(typeId: string, factory: HandleWrapperFactory): void { + handleWrapperRegistry.set(typeId, factory); +} + +/** + * Checks if a value is a marshalled handle and wraps it appropriately. + * Uses the wrapper registry to create typed wrapper instances when available. + * + * @param value - The value to potentially wrap + * @param client - Optional client for creating typed wrapper instances + */ +export function wrapIfHandle(value: unknown, client?: AspireClient): unknown { + if (value && typeof value === 'object') { + if (isMarshalledHandle(value)) { + const handle = new Handle(value); + const typeId = value.$type; + + // Try to find a registered wrapper factory for this type + if (typeId && client) { + const factory = handleWrapperRegistry.get(typeId); + if (factory) { + return factory(handle, client); + } + } + + return handle; + } + } + return value; +} + +// ============================================================================ +// Capability Error +// ============================================================================ + +/** + * Error thrown when an ATS capability invocation fails. + */ +export class CapabilityError extends Error { + constructor( + /** The structured error from the server */ + public readonly error: AtsError + ) { + super(error.message); + this.name = 'CapabilityError'; + } + + /** Machine-readable error code */ + get code(): string { + return this.error.code; + } + + /** The capability that failed (if applicable) */ + get capability(): string | undefined { + return this.error.capability; + } +} + +// ============================================================================ +// Callback Registry +// ============================================================================ + +const callbackRegistry = new Map(); +let callbackIdCounter = 0; + +/** + * Register a callback function that can be invoked from the .NET side. + * Returns a callback ID that should be passed to methods accepting callbacks. + * + * .NET passes arguments as an object with positional keys: `{ p0: value0, p1: value1, ... }` + * This function automatically extracts positional parameters and wraps handles. + * + * @example + * // Single parameter callback + * const id = registerCallback((ctx) => console.log(ctx)); + * // .NET sends: { p0: { $handle: "...", $type: "..." } } + * // Callback receives: Handle instance + * + * @example + * // Multi-parameter callback + * const id = registerCallback((a, b) => console.log(a, b)); + * // .NET sends: { p0: "hello", p1: 42 } + * // Callback receives: "hello", 42 + */ +export function registerCallback( + callback: (...args: any[]) => TResult | Promise +): string { + const callbackId = `callback_${++callbackIdCounter}_${Date.now()}`; + + // Wrap the callback to handle .NET's positional argument format + const wrapper: CallbackFunction = async (args: unknown, client: AspireClient) => { + // .NET sends args as object { p0: value0, p1: value1, ... } + if (args && typeof args === 'object' && !Array.isArray(args)) { + const argObj = args as Record; + const argArray: unknown[] = []; + + // Extract positional parameters (p0, p1, p2, ...) + for (let i = 0; ; i++) { + const key = `p${i}`; + if (key in argObj) { + argArray.push(wrapIfHandle(argObj[key], client)); + } else { + break; + } + } + + if (argArray.length > 0) { + // Spread positional arguments to callback + return await callback(...argArray); + } + + // No positional params found - call with no args + return await callback(); + } + + // Null/undefined - call with no args + if (args === null || args === undefined) { + return await callback(); + } + + // Primitive value - pass as single arg (shouldn't happen with current protocol) + return await callback(wrapIfHandle(args, client)); + }; + + callbackRegistry.set(callbackId, wrapper); + return callbackId; +} + +/** + * Unregister a callback by its ID. + */ +export function unregisterCallback(callbackId: string): boolean { + return callbackRegistry.delete(callbackId); +} + +/** + * Get the number of registered callbacks. + */ +export function getCallbackCount(): number { + return callbackRegistry.size; +} + +// ============================================================================ +// Cancellation Token Registry +// ============================================================================ + +/** + * Registry for cancellation tokens. + * Maps cancellation IDs to cleanup functions. + */ +const cancellationRegistry = new Map void>(); +let cancellationIdCounter = 0; + +/** + * A reference to the current AspireClient for sending cancel requests. + * Set by AspireClient.connect(). + */ +let currentClient: AspireClient | null = null; + +/** + * Register an AbortSignal for cancellation support. + * Returns a cancellation ID that should be passed to methods accepting CancellationToken. + * + * When the AbortSignal is aborted, sends a cancelToken request to the host. + * + * @param signal - The AbortSignal to register (optional) + * @returns The cancellation ID, or undefined if no signal provided + * + * @example + * const controller = new AbortController(); + * const id = registerCancellation(controller.signal); + * // Pass id to capability invocation + * // Later: controller.abort() will cancel the operation + */ +export function registerCancellation(signal?: AbortSignal): string | undefined { + if (!signal) { + return undefined; + } + + // Already aborted? Don't register + if (signal.aborted) { + return undefined; + } + + const cancellationId = `ct_${++cancellationIdCounter}_${Date.now()}`; + + // Set up the abort listener + const onAbort = () => { + // Send cancel request to host + if (currentClient?.connected) { + currentClient.cancelToken(cancellationId).catch(() => { + // Ignore errors - the operation may have already completed + }); + } + // Clean up the listener + cancellationRegistry.delete(cancellationId); + }; + + // Listen for abort + signal.addEventListener('abort', onAbort, { once: true }); + + // Store cleanup function + cancellationRegistry.set(cancellationId, () => { + signal.removeEventListener('abort', onAbort); + }); + + return cancellationId; +} + +/** + * Unregister a cancellation token by its ID. + * Call this when the operation completes to clean up resources. + * + * @param cancellationId - The cancellation ID to unregister + */ +export function unregisterCancellation(cancellationId: string | undefined): void { + if (!cancellationId) { + return; + } + + const cleanup = cancellationRegistry.get(cancellationId); + if (cleanup) { + cleanup(); + cancellationRegistry.delete(cancellationId); + } +} + +// ============================================================================ +// AspireClient (JSON-RPC Connection) +// ============================================================================ + +/** + * Client for connecting to the Aspire AppHost via socket/named pipe. + */ +export class AspireClient { + private connection: rpc.MessageConnection | null = null; + private socket: net.Socket | null = null; + private disconnectCallbacks: (() => void)[] = []; + private _pendingCalls = 0; + + constructor(private socketPath: string) { } + + /** + * Register a callback to be called when the connection is lost + */ + onDisconnect(callback: () => void): void { + this.disconnectCallbacks.push(callback); + } + + private notifyDisconnect(): void { + for (const callback of this.disconnectCallbacks) { + try { + callback(); + } catch { + // Ignore callback errors + } + } + } + + connect(timeoutMs: number = 5000): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('Connection timeout')), timeoutMs); + + // On Windows, use named pipes; on Unix, use Unix domain sockets + const isWindows = process.platform === 'win32'; + const pipePath = isWindows ? `\\\\.\\pipe\\${this.socketPath}` : this.socketPath; + + this.socket = net.createConnection(pipePath); + + this.socket.once('error', (error: Error) => { + clearTimeout(timeout); + reject(error); + }); + + this.socket.once('connect', () => { + clearTimeout(timeout); + try { + const reader = new rpc.SocketMessageReader(this.socket!); + const writer = new rpc.SocketMessageWriter(this.socket!); + this.connection = rpc.createMessageConnection(reader, writer); + + this.connection.onClose(() => { + this.connection = null; + this.notifyDisconnect(); + }); + this.connection.onError((err: any) => console.error('JsonRpc connection error:', err)); + + // Handle callback invocations from the .NET side + this.connection.onRequest('invokeCallback', async (callbackId: string, args: unknown) => { + const callback = callbackRegistry.get(callbackId); + if (!callback) { + throw new Error(`Callback not found: ${callbackId}`); + } + try { + // The registered wrapper handles arg unpacking and handle wrapping + // Pass this client so handles can be wrapped with typed wrapper classes + return await Promise.resolve(callback(args, this)); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Callback execution failed: ${message}`); + } + }); + + this.connection.listen(); + + // Set the current client for cancellation registry + currentClient = this; + + resolve(); + } catch (e) { + reject(e); + } + }); + + this.socket.on('close', () => { + this.connection?.dispose(); + this.connection = null; + if (currentClient === this) { + currentClient = null; + } + this.notifyDisconnect(); + }); + }); + } + + ping(): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('ping'); + } + + /** + * Cancel a CancellationToken by its ID. + * Called when an AbortSignal is aborted. + * + * @param tokenId - The token ID to cancel + * @returns True if the token was found and cancelled, false otherwise + */ + cancelToken(tokenId: string): Promise { + if (!this.connection) return Promise.reject(new Error('Not connected to AppHost')); + return this.connection.sendRequest('cancelToken', tokenId); + } + + /** + * Invoke an ATS capability by ID. + * + * Capabilities are operations exposed by [AspireExport] attributes. + * Results are automatically wrapped in Handle objects when applicable. + * + * @param capabilityId - The capability ID (e.g., "Aspire.Hosting/createBuilder") + * @param args - Arguments to pass to the capability + * @returns The capability result, wrapped as Handle if it's a handle type + * @throws CapabilityError if the capability fails + */ + async invokeCapability( + capabilityId: string, + args?: Record + ): Promise { + if (!this.connection) { + throw new Error('Not connected to AppHost'); + } + + // Ref counting: The vscode-jsonrpc socket keeps Node's event loop alive. + // We ref() during RPC calls so the process doesn't exit mid-call, and + // unref() when idle so the process can exit naturally after all work completes. + if (this._pendingCalls === 0) { + this.socket?.ref(); + } + this._pendingCalls++; + + try { + const result = await this.connection.sendRequest( + 'invokeCapability', + capabilityId, + args ?? null + ); + + // Check for structured error response + if (isAtsError(result)) { + throw new CapabilityError(result.$error); + } + + // Wrap handles automatically + return wrapIfHandle(result, this) as T; + } finally { + this._pendingCalls--; + if (this._pendingCalls === 0) { + this.socket?.unref(); + } + } + } + + disconnect(): void { + try { this.connection?.dispose(); } finally { this.connection = null; } + try { this.socket?.end(); } finally { this.socket = null; } + } + + get connected(): boolean { + return this.connection !== null && this.socket !== null; + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..8e8fa159cc4 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:29550;http://localhost:28731", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10775", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13119" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..0d0d1c5b3cf --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/apphost.ts @@ -0,0 +1,42 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const staticFilesSource = await builder.addContainer("static-files-source", "nginx"); +const backend = await builder.addContainer("backend", "nginx") + .withHttpEndpoint({ name: "http", targetPort: 80 }); + +const proxy = await builder.addYarp("proxy") + .withHostPort({ port: 8080 }) + .withHostHttpsPort({ port: 8443 }) + .publishWithStaticFiles(staticFilesSource); + +await proxy.withConfiguration(async (config) => { + const endpoint = await backend.getEndpoint("http"); + const cluster = await config.addCluster(endpoint); + + await config.addRoute("/{**catchall}", cluster) + .withTransformXForwarded() + .withTransformForwarded() + .withTransformClientCertHeader("X-Client-Cert") + .withTransformHttpMethodChange("GET", "POST") + .withTransformQueryValue("source", "apphost") + .withTransformQueryRouteValue("routeId", "id") + .withTransformQueryRemoveKey("remove") + .withTransformCopyRequestHeaders() + .withTransformUseOriginalHostHeader() + .withTransformRequestHeader("X-Test-Header", "test-value") + .withTransformRequestHeaderRouteValue("X-Route-Value", "id") + .withTransformRequestHeaderRemove("X-Remove-Request") + .withTransformRequestHeadersAllowed(["X-Test-Header", "X-Route-Value"]) + .withTransformCopyResponseHeaders() + .withTransformCopyResponseTrailers() + .withTransformResponseHeader("X-Response-Header", "response-value") + .withTransformResponseHeaderRemove("X-Remove-Response") + .withTransformResponseHeadersAllowed(["X-Response-Header"]) + .withTransformResponseTrailer("X-Response-Trailer", "trailer-value") + .withTransformResponseTrailerRemove("X-Remove-Trailer") + .withTransformResponseTrailersAllowed(["X-Response-Trailer"]); +}); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Yarp/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/src/Aspire.Cli/Backchannel/IAppHostAuxiliaryBackchannel.cs b/src/Aspire.Cli/Backchannel/IAppHostAuxiliaryBackchannel.cs index 6c3d8448b9c..13e394be142 100644 --- a/src/Aspire.Cli/Backchannel/IAppHostAuxiliaryBackchannel.cs +++ b/src/Aspire.Cli/Backchannel/IAppHostAuxiliaryBackchannel.cs @@ -112,7 +112,7 @@ Task CallResourceMcpToolAsync( /// Executes a command on a resource. /// /// The name of the resource. - /// The name of the command (e.g., "resource-start", "resource-stop", "resource-restart"). + /// The name of the command (e.g., "start", "stop", "restart"). /// Cancellation token. /// The result of the command execution. Task ExecuteResourceCommandAsync( diff --git a/src/Aspire.Cli/Commands/NewCommand.cs b/src/Aspire.Cli/Commands/NewCommand.cs index 41b75856014..9bfe82dd8df 100644 --- a/src/Aspire.Cli/Commands/NewCommand.cs +++ b/src/Aspire.Cli/Commands/NewCommand.cs @@ -23,6 +23,7 @@ internal sealed class NewCommand : BaseCommand, IPackageMetaPrefetchingCommand internal override HelpGroup HelpGroup => HelpGroup.AppCommands; private readonly INewCommandPrompter _prompter; + private readonly ITemplateProvider _templateProvider; private readonly ITemplate[] _templates; private readonly IFeatures _features; private readonly IPackagingService _packagingService; @@ -75,6 +76,7 @@ public NewCommand( : base("new", NewCommandStrings.Description, features, updateNotifier, executionContext, interactionService, telemetry) { _prompter = prompter; + _templateProvider = templateProvider; _features = features; _packagingService = packagingService; _configurationService = configurationService; @@ -102,7 +104,11 @@ public NewCommand( }; Options.Add(_languageOption); - _templates = templateProvider.GetTemplatesAsync(CancellationToken.None).GetAwaiter().GetResult().ToArray(); + // Register template definitions as subcommands synchronously. + // This uses GetTemplates() which returns template definitions without + // performing any async I/O (e.g. SDK availability checks). Runtime + // availability is checked in ExecuteAsync via GetTemplatesAsync(). + _templates = templateProvider.GetTemplates().ToArray(); foreach (var template in _templates) { @@ -199,10 +205,10 @@ private async Task PromptForAppHostLanguageAsync(IReadOnlyList s return (true, selectedLanguageId); } - private ITemplate[] GetTemplatesForPrompt(ParseResult parseResult) + private ITemplate[] GetTemplatesForPrompt(ITemplate[] availableTemplates, ParseResult parseResult) { var explicitLanguageId = ParseExplicitLanguageId(parseResult); - var templatesForPrompt = _templates.ToList(); + var templatesForPrompt = availableTemplates.ToList(); if (!string.IsNullOrWhiteSpace(explicitLanguageId)) { @@ -214,19 +220,24 @@ private ITemplate[] GetTemplatesForPrompt(ParseResult parseResult) return templatesForPrompt.ToArray(); } - private async Task GetProjectTemplateAsync(ParseResult parseResult, CancellationToken cancellationToken) + private async Task GetProjectTemplateAsync(ITemplate[] availableTemplates, ParseResult parseResult, CancellationToken cancellationToken) { // If a subcommand was matched (e.g., aspire new aspire-starter), find the template by command name if (parseResult.CommandResult.Command != this) { - var subcommandTemplate = _templates.SingleOrDefault(t => t.Name.Equals(parseResult.CommandResult.Command.Name, StringComparison.OrdinalIgnoreCase)); + var subcommandTemplate = availableTemplates.SingleOrDefault(t => t.Name.Equals(parseResult.CommandResult.Command.Name, StringComparison.OrdinalIgnoreCase)); if (subcommandTemplate is not null) { return subcommandTemplate; } + + // The template subcommand was parsed successfully but the template is + // not available at runtime (e.g. .NET SDK is not installed). + InteractionService.DisplayError($"Template '{parseResult.CommandResult.Command.Name}' is not available. Ensure the required runtime is installed."); + return null; } - var templatesForPrompt = GetTemplatesForPrompt(parseResult); + var templatesForPrompt = GetTemplatesForPrompt(availableTemplates, parseResult); if (templatesForPrompt.Length == 0) { InteractionService.DisplayError("No templates are available for the current environment."); @@ -301,7 +312,12 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell { using var activity = Telemetry.StartDiagnosticActivity(this.Name); - var template = await GetProjectTemplateAsync(parseResult, cancellationToken); + // Resolve which templates are actually available at runtime (performs + // async checks like SDK availability). This may be a subset of the + // templates registered as subcommands. + var availableTemplates = (await _templateProvider.GetTemplatesAsync(cancellationToken)).ToArray(); + + var template = await GetProjectTemplateAsync(availableTemplates, parseResult, cancellationToken); if (template is null) { return ExitCodeConstants.InvalidCommand; diff --git a/src/Aspire.Cli/Commands/ResourceCommand.cs b/src/Aspire.Cli/Commands/ResourceCommand.cs index 248951a7877..9e3d07a71e2 100644 --- a/src/Aspire.Cli/Commands/ResourceCommand.cs +++ b/src/Aspire.Cli/Commands/ResourceCommand.cs @@ -33,6 +33,17 @@ internal sealed class ResourceCommand : BaseCommand private static readonly OptionWithLegacy s_appHostOption = new("--apphost", "--project", SharedCommandStrings.AppHostOptionDescription); + /// + /// Well-known commands with their display metadata. + /// The command name is used directly (no mapping needed since the user-facing names match the actual command names). + /// + private static readonly Dictionary s_wellKnownCommands = new(StringComparer.OrdinalIgnoreCase) + { + ["start"] = ("Starting", "start", "started"), + ["stop"] = ("Stopping", "stop", "stopped"), + ["restart"] = ("Restarting", "restart", "restarted"), + }; + public ResourceCommand( IInteractionService interactionService, IAuxiliaryBackchannelMonitor backchannelMonitor, @@ -41,7 +52,7 @@ public ResourceCommand( CliExecutionContext executionContext, ILogger logger, AspireCliTelemetry telemetry) - : base("command", ResourceCommandStrings.CommandDescription, features, updateNotifier, executionContext, interactionService, telemetry) + : base("resource", ResourceCommandStrings.CommandDescription, features, updateNotifier, executionContext, interactionService, telemetry) { _interactionService = interactionService; _connectionResolver = new AppHostConnectionResolver(backchannelMonitor, interactionService, executionContext, logger); @@ -71,6 +82,21 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell return ExitCodeConstants.FailedToFindProject; } + // Map well-known friendly names (start/stop/restart) to their display metadata + if (s_wellKnownCommands.TryGetValue(commandName, out var knownCommand)) + { + return await ResourceCommandHelper.ExecuteResourceCommandAsync( + result.Connection!, + _interactionService, + _logger, + resourceName, + commandName, + knownCommand.ProgressVerb, + knownCommand.BaseVerb, + knownCommand.PastTenseVerb, + cancellationToken); + } + return await ResourceCommandHelper.ExecuteGenericCommandAsync( result.Connection!, _interactionService, diff --git a/src/Aspire.Cli/Commands/ResourceCommandBase.cs b/src/Aspire.Cli/Commands/ResourceCommandBase.cs deleted file mode 100644 index 3a0484c2bc3..00000000000 --- a/src/Aspire.Cli/Commands/ResourceCommandBase.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.CommandLine; -using System.Globalization; -using Aspire.Cli.Backchannel; -using Aspire.Cli.Configuration; -using Aspire.Cli.Interaction; -using Aspire.Cli.Resources; -using Aspire.Cli.Telemetry; -using Aspire.Cli.Utils; -using Microsoft.Extensions.Logging; - -namespace Aspire.Cli.Commands; - -/// -/// Base class for commands that execute resource lifecycle operations (start, restart, etc.). -/// -internal abstract class ResourceCommandBase : BaseCommand -{ - protected readonly AppHostConnectionResolver ConnectionResolver; - protected readonly ILogger Logger; - - private readonly Argument _resourceArgument; - - protected static readonly OptionWithLegacy s_appHostOption = new("--apphost", "--project", SharedCommandStrings.AppHostOptionDescription); - - /// - /// The resource command name to execute (e.g., KnownResourceCommands.StartCommand). - /// - protected abstract string CommandName { get; } - - /// - /// The verb to display during progress (e.g., "Starting"). - /// - protected abstract string ProgressVerb { get; } - - /// - /// The base verb for error messages (e.g., "start"). - /// - protected abstract string BaseVerb { get; } - - /// - /// The past tense verb for success messages (e.g., "started"). - /// - protected abstract string PastTenseVerb { get; } - - /// - /// The description for the resource argument. - /// - protected abstract string ResourceArgumentDescription { get; } - - protected ResourceCommandBase( - string name, - string description, - IInteractionService interactionService, - IAuxiliaryBackchannelMonitor backchannelMonitor, - IFeatures features, - ICliUpdateNotifier updateNotifier, - CliExecutionContext executionContext, - ILogger logger, - AspireCliTelemetry telemetry) - : base(name, description, features, updateNotifier, executionContext, interactionService, telemetry) - { - ConnectionResolver = new AppHostConnectionResolver(backchannelMonitor, interactionService, executionContext, logger); - Logger = logger; - - _resourceArgument = new Argument("resource") - { - Description = ResourceArgumentDescription - }; - - Arguments.Add(_resourceArgument); - Options.Add(s_appHostOption); - } - - protected override async Task ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken) - { - var resourceName = parseResult.GetValue(_resourceArgument)!; - var passedAppHostProjectFile = parseResult.GetValue(s_appHostOption); - - var result = await ConnectionResolver.ResolveConnectionAsync( - passedAppHostProjectFile, - SharedCommandStrings.ScanningForRunningAppHosts, - string.Format(CultureInfo.CurrentCulture, SharedCommandStrings.SelectAppHost, ResourceCommandStrings.SelectAppHostAction), - SharedCommandStrings.AppHostNotRunning, - cancellationToken); - - if (!result.Success) - { - InteractionService.DisplayError(result.ErrorMessage); - return ExitCodeConstants.FailedToFindProject; - } - - return await ResourceCommandHelper.ExecuteResourceCommandAsync( - result.Connection!, - InteractionService, - Logger, - resourceName, - CommandName, - ProgressVerb, - BaseVerb, - PastTenseVerb, - cancellationToken); - } -} diff --git a/src/Aspire.Cli/Commands/ResourceCommandHelper.cs b/src/Aspire.Cli/Commands/ResourceCommandHelper.cs index 648e18c9c50..4db1f3753a3 100644 --- a/src/Aspire.Cli/Commands/ResourceCommandHelper.cs +++ b/src/Aspire.Cli/Commands/ResourceCommandHelper.cs @@ -20,7 +20,7 @@ internal static class ResourceCommandHelper /// The interaction service for user feedback. /// The logger for debug output. /// The name of the resource. - /// The command to execute (e.g., "resource-start"). + /// The command to execute (e.g., "start"). /// The verb to display during progress (e.g., "Starting", "Stopping"). /// The base verb for error messages (e.g., "start", "stop"). /// The past tense verb for success messages (e.g., "started", "stopped"). diff --git a/src/Aspire.Cli/Commands/RestartCommand.cs b/src/Aspire.Cli/Commands/RestartCommand.cs deleted file mode 100644 index 9979d25241e..00000000000 --- a/src/Aspire.Cli/Commands/RestartCommand.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Aspire.Cli.Backchannel; -using Aspire.Cli.Configuration; -using Aspire.Cli.Interaction; -using Aspire.Cli.Resources; -using Aspire.Cli.Telemetry; -using Aspire.Cli.Utils; -using Aspire.Hosting.ApplicationModel; -using Microsoft.Extensions.Logging; - -namespace Aspire.Cli.Commands; - -internal sealed class RestartCommand : ResourceCommandBase -{ - internal override HelpGroup HelpGroup => HelpGroup.ResourceManagement; - - protected override string CommandName => KnownResourceCommands.RestartCommand; - protected override string ProgressVerb => "Restarting"; - protected override string BaseVerb => "restart"; - protected override string PastTenseVerb => "restarted"; - protected override string ResourceArgumentDescription => ResourceCommandStrings.RestartResourceArgumentDescription; - - public RestartCommand( - IInteractionService interactionService, - IAuxiliaryBackchannelMonitor backchannelMonitor, - IFeatures features, - ICliUpdateNotifier updateNotifier, - CliExecutionContext executionContext, - ILogger logger, - AspireCliTelemetry telemetry) - : base("restart", ResourceCommandStrings.RestartDescription, - interactionService, backchannelMonitor, features, updateNotifier, - executionContext, logger, telemetry) - { - } -} diff --git a/src/Aspire.Cli/Commands/RootCommand.cs b/src/Aspire.Cli/Commands/RootCommand.cs index 1b1148075fc..43fe3bfb7b6 100644 --- a/src/Aspire.Cli/Commands/RootCommand.cs +++ b/src/Aspire.Cli/Commands/RootCommand.cs @@ -112,7 +112,6 @@ public RootCommand( RunCommand runCommand, StopCommand stopCommand, StartCommand startCommand, - RestartCommand restartCommand, WaitCommand waitCommand, ResourceCommand commandCommand, PsCommand psCommand, @@ -200,7 +199,6 @@ public RootCommand( Subcommands.Add(runCommand); Subcommands.Add(stopCommand); Subcommands.Add(startCommand); - Subcommands.Add(restartCommand); Subcommands.Add(waitCommand); Subcommands.Add(commandCommand); Subcommands.Add(psCommand); diff --git a/src/Aspire.Cli/Commands/Sdk/SdkDumpCommand.cs b/src/Aspire.Cli/Commands/Sdk/SdkDumpCommand.cs index ca1e6b6c66f..79d83d3f9a2 100644 --- a/src/Aspire.Cli/Commands/Sdk/SdkDumpCommand.cs +++ b/src/Aspire.Cli/Commands/Sdk/SdkDumpCommand.cs @@ -122,39 +122,34 @@ private async Task DumpCapabilitiesAsync( try { - // TODO: Support bundle mode by using DLL references instead of project references. - // In bundle mode, we'd need to add integration DLLs to the probing path rather than - // using additionalProjectReferences. For now, SDK dump only works with .NET SDK. - var appHostServerProjectInterface = await _appHostServerProjectFactory.CreateAsync(tempDir, cancellationToken); - if (appHostServerProjectInterface is not DotNetBasedAppHostServerProject appHostServerProject) + var appHostServerProject = await _appHostServerProjectFactory.CreateAsync(tempDir, cancellationToken); + + // Build integrations list - optional integration project reference + var integrations = new List(); + + if (integrationProject is not null) { - InteractionService.DisplayError("SDK dump is only available with .NET SDK installed."); - return ExitCodeConstants.FailedToBuildArtifacts; + integrations.Add(IntegrationReference.FromProject( + Path.GetFileNameWithoutExtension(integrationProject.FullName), + integrationProject.FullName)); } - // Build packages list - empty since we only need core capabilities + optional integration - var packages = new List<(string Name, string Version)>(); - _logger.LogDebug("Building AppHost server for capability scanning"); - // Create project files with the integration project reference if specified - var additionalProjectRefs = integrationProject is not null - ? new[] { integrationProject.FullName } - : null; + var prepareResult = await appHostServerProject.PrepareAsync( + VersionHelper.GetDefaultTemplateVersion(), + integrations, + cancellationToken); - await appHostServerProject.CreateProjectFilesAsync( - packages, - cancellationToken, - additionalProjectReferences: additionalProjectRefs); - - var (buildSuccess, buildOutput) = await appHostServerProject.BuildAsync(cancellationToken); - - if (!buildSuccess) + if (!prepareResult.Success) { InteractionService.DisplayError("Failed to build capability scanner."); - foreach (var (_, line) in buildOutput.GetLines()) + if (prepareResult.Output is not null) { - InteractionService.DisplayMessage(KnownEmojis.Wrench, line); + foreach (var (_, line) in prepareResult.Output.GetLines()) + { + InteractionService.DisplayMessage(KnownEmojis.Wrench, line); + } } return ExitCodeConstants.FailedToBuildArtifacts; } diff --git a/src/Aspire.Cli/Commands/Sdk/SdkGenerateCommand.cs b/src/Aspire.Cli/Commands/Sdk/SdkGenerateCommand.cs index 57264718cd5..5935fdc9561 100644 --- a/src/Aspire.Cli/Commands/Sdk/SdkGenerateCommand.cs +++ b/src/Aspire.Cli/Commands/Sdk/SdkGenerateCommand.cs @@ -120,42 +120,40 @@ private async Task GenerateSdkAsync( try { - // TODO: Support bundle mode by using DLL references instead of project references. - // In bundle mode, we'd need to add integration DLLs to the probing path rather than - // using additionalProjectReferences. For now, SDK generation only works with .NET SDK. - var appHostServerProjectInterface = await _appHostServerProjectFactory.CreateAsync(tempDir, cancellationToken); - if (appHostServerProjectInterface is not DotNetBasedAppHostServerProject appHostServerProject) - { - InteractionService.DisplayError("SDK generation is only available with .NET SDK installed."); - return ExitCodeConstants.FailedToBuildArtifacts; - } + var appHostServerProject = await _appHostServerProjectFactory.CreateAsync(tempDir, cancellationToken); // Get code generation package for the target language var codeGenPackage = await _languageDiscovery.GetPackageForLanguageAsync(languageInfo.LanguageId, cancellationToken); - // Build packages list - include the code generator - var packages = new List<(string Name, string Version)>(); + // Build integrations list — the integration project brings Aspire.Hosting transitively; + // we only need to add the codegen package and the project reference itself. + var integrations = new List(); if (codeGenPackage is not null) { - packages.Add((codeGenPackage, DotNetBasedAppHostServerProject.DefaultSdkVersion)); + integrations.Add(IntegrationReference.FromPackage(codeGenPackage, VersionHelper.GetDefaultTemplateVersion())); } - _logger.LogDebug("Building AppHost server for SDK generation"); + // Add the integration project as a project reference + integrations.Add(IntegrationReference.FromProject( + Path.GetFileNameWithoutExtension(integrationProject.FullName), + integrationProject.FullName)); - // Create project files with the integration project reference - await appHostServerProject.CreateProjectFilesAsync( - packages, - cancellationToken, - additionalProjectReferences: [integrationProject.FullName]); + _logger.LogDebug("Building AppHost server for SDK generation"); - var (buildSuccess, buildOutput) = await appHostServerProject.BuildAsync(cancellationToken); + var prepareResult = await appHostServerProject.PrepareAsync( + VersionHelper.GetDefaultTemplateVersion(), + integrations, + cancellationToken); - if (!buildSuccess) + if (!prepareResult.Success) { InteractionService.DisplayError("Failed to build SDK generation server."); - foreach (var (_, line) in buildOutput.GetLines()) + if (prepareResult.Output is not null) { - InteractionService.DisplayMessage(KnownEmojis.Wrench, line); + foreach (var (_, line) in prepareResult.Output.GetLines()) + { + InteractionService.DisplayMessage(KnownEmojis.Wrench, line); + } } return ExitCodeConstants.FailedToBuildArtifacts; } diff --git a/src/Aspire.Cli/Commands/StartCommand.cs b/src/Aspire.Cli/Commands/StartCommand.cs index 19e82971690..8fc1be7d9f8 100644 --- a/src/Aspire.Cli/Commands/StartCommand.cs +++ b/src/Aspire.Cli/Commands/StartCommand.cs @@ -2,32 +2,20 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.CommandLine; -using System.Globalization; -using Aspire.Cli.Backchannel; using Aspire.Cli.Configuration; using Aspire.Cli.Interaction; using Aspire.Cli.Resources; using Aspire.Cli.Telemetry; using Aspire.Cli.Utils; -using Aspire.Hosting.ApplicationModel; -using Microsoft.Extensions.Logging; namespace Aspire.Cli.Commands; internal sealed class StartCommand : BaseCommand { - internal override HelpGroup HelpGroup => HelpGroup.ResourceManagement; + internal override HelpGroup HelpGroup => HelpGroup.AppCommands; - private readonly IInteractionService _interactionService; - private readonly AppHostConnectionResolver _connectionResolver; private readonly AppHostLauncher _appHostLauncher; - private readonly ILogger _logger; - - private static readonly Argument s_resourceArgument = new("resource") - { - Description = ResourceCommandStrings.StartResourceArgumentDescription, - Arity = ArgumentArity.ZeroOrOne - }; + private readonly IInteractionService _interactionService; private static readonly Option s_noBuildOption = new("--no-build") { @@ -36,22 +24,17 @@ internal sealed class StartCommand : BaseCommand public StartCommand( IInteractionService interactionService, - IAuxiliaryBackchannelMonitor backchannelMonitor, IFeatures features, ICliUpdateNotifier updateNotifier, CliExecutionContext executionContext, - ILogger logger, AspireCliTelemetry telemetry, AppHostLauncher appHostLauncher) - : base("start", ResourceCommandStrings.StartDescription, + : base("start", StartCommandStrings.Description, features, updateNotifier, executionContext, interactionService, telemetry) { _interactionService = interactionService; - _connectionResolver = new AppHostConnectionResolver(backchannelMonitor, interactionService, executionContext, logger); _appHostLauncher = appHostLauncher; - _logger = logger; - Arguments.Add(s_resourceArgument); Options.Add(s_noBuildOption); AppHostLauncher.AddLaunchOptions(this); @@ -60,30 +43,10 @@ public StartCommand( protected override async Task ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken) { - var resourceName = parseResult.GetValue(s_resourceArgument); var passedAppHostProjectFile = parseResult.GetValue(AppHostLauncher.s_appHostOption); var format = parseResult.GetValue(AppHostLauncher.s_formatOption); var isolated = parseResult.GetValue(AppHostLauncher.s_isolatedOption); - // If a resource name is provided, start that specific resource - if (!string.IsNullOrEmpty(resourceName)) - { - if (format == OutputFormat.Json) - { - _interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, ResourceCommandStrings.OptionNotValidWithResource, "--format")); - return ExitCodeConstants.InvalidCommand; - } - - if (isolated) - { - _interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, ResourceCommandStrings.OptionNotValidWithResource, "--isolated")); - return ExitCodeConstants.InvalidCommand; - } - - return await StartResourceAsync(passedAppHostProjectFile, resourceName, cancellationToken); - } - - // No resource specified — start the AppHost in detached mode var noBuild = parseResult.GetValue(s_noBuildOption); var isExtensionHost = ExtensionHelper.IsExtensionHost(_interactionService, out _, out _); var globalArgs = RootCommand.GetChildProcessArgs(parseResult); @@ -103,31 +66,4 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell additionalArgs, cancellationToken); } - - private async Task StartResourceAsync(FileInfo? passedAppHostProjectFile, string resourceName, CancellationToken cancellationToken) - { - var result = await _connectionResolver.ResolveConnectionAsync( - passedAppHostProjectFile, - SharedCommandStrings.ScanningForRunningAppHosts, - string.Format(CultureInfo.CurrentCulture, SharedCommandStrings.SelectAppHost, ResourceCommandStrings.SelectAppHostAction), - SharedCommandStrings.AppHostNotRunning, - cancellationToken); - - if (!result.Success) - { - _interactionService.DisplayError(result.ErrorMessage); - return ExitCodeConstants.FailedToFindProject; - } - - return await ResourceCommandHelper.ExecuteResourceCommandAsync( - result.Connection!, - _interactionService, - _logger, - resourceName, - KnownResourceCommands.StartCommand, - "Starting", - "start", - "started", - cancellationToken); - } } diff --git a/src/Aspire.Cli/Commands/StopCommand.cs b/src/Aspire.Cli/Commands/StopCommand.cs index 2123fb3eea5..9969d0c22a2 100644 --- a/src/Aspire.Cli/Commands/StopCommand.cs +++ b/src/Aspire.Cli/Commands/StopCommand.cs @@ -11,7 +11,6 @@ using Aspire.Cli.Resources; using Aspire.Cli.Telemetry; using Aspire.Cli.Utils; -using Aspire.Hosting.ApplicationModel; using Microsoft.Extensions.Logging; namespace Aspire.Cli.Commands; @@ -26,12 +25,6 @@ internal sealed class StopCommand : BaseCommand private readonly ICliHostEnvironment _hostEnvironment; private readonly TimeProvider _timeProvider; - private static readonly Argument s_resourceArgument = new("resource") - { - Description = "The name of the resource to stop. If not specified, stops the entire AppHost.", - Arity = ArgumentArity.ZeroOrOne - }; - private static readonly OptionWithLegacy s_appHostOption = new("--apphost", "--project", StopCommandStrings.ProjectArgumentDescription); private static readonly Option s_allOption = new("--all") @@ -57,14 +50,12 @@ public StopCommand( _logger = logger; _timeProvider = timeProvider ?? TimeProvider.System; - Arguments.Add(s_resourceArgument); Options.Add(s_appHostOption); Options.Add(s_allOption); } protected override async Task ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken) { - var resourceName = parseResult.GetValue(s_resourceArgument); var passedAppHostProjectFile = parseResult.GetValue(s_appHostOption); var stopAll = parseResult.GetValue(s_allOption); @@ -75,13 +66,6 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell return ExitCodeConstants.FailedToFindProject; } - // Validate mutual exclusivity of --all and resource argument - if (stopAll && !string.IsNullOrEmpty(resourceName)) - { - _interactionService.DisplayError(string.Format(CultureInfo.InvariantCulture, StopCommandStrings.AllAndResourceMutuallyExclusive, s_allOption.Name)); - return ExitCodeConstants.FailedToFindProject; - } - // Handle --all: stop all running AppHosts if (stopAll) { @@ -91,22 +75,22 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell // In non-interactive mode, try to auto-resolve without prompting if (!_hostEnvironment.SupportsInteractiveInput) { - return await ExecuteNonInteractiveAsync(passedAppHostProjectFile, resourceName, cancellationToken); + return await ExecuteNonInteractiveAsync(passedAppHostProjectFile, cancellationToken); } - return await ExecuteInteractiveAsync(passedAppHostProjectFile, resourceName, cancellationToken); + return await ExecuteInteractiveAsync(passedAppHostProjectFile, cancellationToken); } /// /// Handles the stop command in non-interactive mode by auto-resolving a single AppHost /// or returning an error when multiple AppHosts are running. /// - private async Task ExecuteNonInteractiveAsync(FileInfo? passedAppHostProjectFile, string? resourceName, CancellationToken cancellationToken) + private async Task ExecuteNonInteractiveAsync(FileInfo? passedAppHostProjectFile, CancellationToken cancellationToken) { // If --project is specified, use the standard resolver (no prompting needed) if (passedAppHostProjectFile is not null) { - return await ExecuteInteractiveAsync(passedAppHostProjectFile, resourceName, cancellationToken); + return await ExecuteInteractiveAsync(passedAppHostProjectFile, cancellationToken); } // Scan for all running AppHosts @@ -128,10 +112,6 @@ private async Task ExecuteNonInteractiveAsync(FileInfo? passedAppHostProjec if (inScopeConnections.Length == 1) { var connection = inScopeConnections[0].Connection!; - if (!string.IsNullOrEmpty(resourceName)) - { - return await StopResourceAsync(connection, resourceName, cancellationToken); - } return await StopAppHostAsync(connection, cancellationToken); } @@ -143,7 +123,7 @@ private async Task ExecuteNonInteractiveAsync(FileInfo? passedAppHostProjec /// /// Handles the stop command in interactive mode, prompting the user to select an AppHost if multiple are running. /// - private async Task ExecuteInteractiveAsync(FileInfo? passedAppHostProjectFile, string? resourceName, CancellationToken cancellationToken) + private async Task ExecuteInteractiveAsync(FileInfo? passedAppHostProjectFile, CancellationToken cancellationToken) { var result = await _connectionResolver.ResolveConnectionAsync( passedAppHostProjectFile, @@ -158,14 +138,7 @@ private async Task ExecuteInteractiveAsync(FileInfo? passedAppHostProjectFi return ExitCodeConstants.Success; } - var selectedConnection = result.Connection!; - - if (!string.IsNullOrEmpty(resourceName)) - { - return await StopResourceAsync(selectedConnection, resourceName, cancellationToken); - } - - return await StopAppHostAsync(selectedConnection, cancellationToken); + return await StopAppHostAsync(result.Connection!, cancellationToken); } /// @@ -337,20 +310,4 @@ private static void SendStopSignal(int pid) } } - /// - /// Stops a specific resource instead of the entire AppHost. - /// - private Task StopResourceAsync(IAppHostAuxiliaryBackchannel connection, string resourceName, CancellationToken cancellationToken) - { - return ResourceCommandHelper.ExecuteResourceCommandAsync( - connection, - _interactionService, - _logger, - resourceName, - KnownResourceCommands.StopCommand, - "Stopping", - "stop", - "stopped", - cancellationToken); - } } diff --git a/src/Aspire.Cli/Configuration/AspireJsonConfiguration.cs b/src/Aspire.Cli/Configuration/AspireJsonConfiguration.cs index 3b25cc8785d..609f5929fd4 100644 --- a/src/Aspire.Cli/Configuration/AspireJsonConfiguration.cs +++ b/src/Aspire.Cli/Configuration/AspireJsonConfiguration.cs @@ -172,24 +172,27 @@ public string GetEffectiveSdkVersion(string defaultSdkVersion) } /// - /// Gets all package references including the base Aspire.Hosting package. - /// Empty package versions in settings are resolved to the effective SDK version. + /// Gets all integration references (both NuGet packages and project references) + /// including the base Aspire.Hosting package. + /// A value ending in ".csproj" is treated as a project reference; otherwise as a NuGet version. + /// Empty package versions are resolved to the effective SDK version. /// /// Default SDK version to use when not configured. - /// Enumerable of (PackageName, Version) tuples. - public IEnumerable<(string Name, string Version)> GetAllPackages(string defaultSdkVersion) + /// The directory containing .aspire/settings.json, used to resolve relative project paths. + /// Enumerable of IntegrationReference objects. + public IEnumerable GetIntegrationReferences(string defaultSdkVersion, string settingsDirectory) { var sdkVersion = GetEffectiveSdkVersion(defaultSdkVersion); - // Base package always included (Aspire.Hosting.AppHost is an SDK, not a runtime DLL) - yield return ("Aspire.Hosting", sdkVersion); + // Base package always included + yield return IntegrationReference.FromPackage("Aspire.Hosting", sdkVersion); if (Packages is null) { yield break; } - foreach (var (packageName, version) in Packages) + foreach (var (packageName, value) in Packages) { // Skip base packages and SDK-only packages if (string.Equals(packageName, "Aspire.Hosting", StringComparison.OrdinalIgnoreCase) || @@ -198,21 +201,27 @@ public string GetEffectiveSdkVersion(string defaultSdkVersion) continue; } - yield return (packageName, string.IsNullOrWhiteSpace(version) ? sdkVersion : version); + var trimmedValue = value?.Trim(); + + if (string.IsNullOrEmpty(trimmedValue)) + { + // NuGet package reference with no explicit version — fall back to the SDK version + yield return IntegrationReference.FromPackage(packageName, sdkVersion); + continue; + } + + if (trimmedValue.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)) + { + // Project reference — resolve relative path to absolute + var absolutePath = Path.GetFullPath(Path.Combine(settingsDirectory, trimmedValue)); + yield return IntegrationReference.FromProject(packageName, absolutePath); + } + else + { + // NuGet package reference with explicit version + yield return IntegrationReference.FromPackage(packageName, trimmedValue); + } } } - /// - /// Gets all package references including the base Aspire.Hosting packages. - /// Uses the SdkVersion for base packages. - /// Note: Aspire.Hosting.AppHost is an SDK package (not a runtime DLL) and is excluded. - /// - /// Enumerable of (PackageName, Version) tuples. - public IEnumerable<(string Name, string Version)> GetAllPackages() - { - var sdkVersion = !string.IsNullOrWhiteSpace(SdkVersion) - ? SdkVersion - : throw new InvalidOperationException("SdkVersion must be set to a non-empty value before calling GetAllPackages. Use LoadOrCreate to ensure it's set."); - return GetAllPackages(sdkVersion); - } } diff --git a/src/Aspire.Cli/Configuration/ConfigurationService.cs b/src/Aspire.Cli/Configuration/ConfigurationService.cs index f079a403587..00aedf75edc 100644 --- a/src/Aspire.Cli/Configuration/ConfigurationService.cs +++ b/src/Aspire.Cli/Configuration/ConfigurationService.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Text.Json; using System.Text.Json.Nodes; using Aspire.Cli.Utils; using Microsoft.Extensions.Configuration; @@ -33,16 +32,7 @@ public async Task SetConfigurationAsync(string key, string value, bool isGlobal // Set the configuration value using dot notation support SetNestedValue(settings, key, value); - // Ensure directory exists - var directory = Path.GetDirectoryName(settingsFilePath); - if (directory is not null && !Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - // Write the updated settings - var jsonContent = JsonSerializer.Serialize(settings, JsonSourceGenerationContext.Default.JsonObject); - await File.WriteAllTextAsync(settingsFilePath, jsonContent, cancellationToken); + await ConfigurationHelper.WriteSettingsFileAsync(settingsFilePath, settings, cancellationToken); } public async Task DeleteConfigurationAsync(string key, bool isGlobal = false, CancellationToken cancellationToken = default) @@ -76,9 +66,7 @@ public async Task DeleteConfigurationAsync(string key, bool isGlobal = fal if (deleted) { - // Write the updated settings - var jsonContent = JsonSerializer.Serialize(settings, JsonSourceGenerationContext.Default.JsonObject); - await File.WriteAllTextAsync(settingsFilePath, jsonContent, cancellationToken); + await ConfigurationHelper.WriteSettingsFileAsync(settingsFilePath, settings, cancellationToken); } return deleted; @@ -180,6 +168,11 @@ private static async Task LoadConfigurationFromFileAsync(string filePath, Dictio /// private static void SetNestedValue(JsonObject settings, string key, string value) { + // Normalize colon-separated keys to dot notation since both represent + // the same configuration hierarchy (e.g., "features:polyglotSupportEnabled" + // is equivalent to "features.polyglotSupportEnabled") + key = key.Replace(':', '.'); + var keyParts = key.Split('.'); // Remove any conflicting flattened keys (e.g., "features:showAllTemplates" when setting "features.showAllTemplates") @@ -238,7 +231,15 @@ private static void RemoveConflictingFlattenedKeys(JsonObject settings, string[] /// private static bool DeleteNestedValue(JsonObject settings, string key) { + // Normalize colon-separated keys to dot notation + key = key.Replace(':', '.'); + var keyParts = key.Split('.'); + + // Remove any flat colon-separated key at root level (legacy format) + var flattenedKey = string.Join(":", keyParts); + var removedFlat = settings.Remove(flattenedKey); + var currentObject = settings; var objectPath = new List<(JsonObject obj, string key)>(); @@ -250,7 +251,7 @@ private static bool DeleteNestedValue(JsonObject settings, string key) if (!currentObject.ContainsKey(part) || currentObject[part] is not JsonObject) { - return false; // Path doesn't exist + return removedFlat; // Path doesn't exist, but may have removed flat key } currentObject = currentObject[part]!.AsObject(); @@ -261,7 +262,7 @@ private static bool DeleteNestedValue(JsonObject settings, string key) // Check if the final key exists if (!currentObject.ContainsKey(finalKey)) { - return false; + return removedFlat; } // Remove the final key @@ -294,7 +295,9 @@ private static void FlattenJsonObject(JsonObject obj, Dictionary { foreach (var kvp in obj) { - var key = string.IsNullOrEmpty(prefix) ? kvp.Key : $"{prefix}.{kvp.Key}"; + // Normalize colon-separated keys to dot notation for consistent display + var normalizedKey = kvp.Key.Replace(':', '.'); + var key = string.IsNullOrEmpty(prefix) ? normalizedKey : $"{prefix}.{normalizedKey}"; if (kvp.Value is JsonObject nestedObj) { diff --git a/src/Aspire.Cli/Configuration/IntegrationReference.cs b/src/Aspire.Cli/Configuration/IntegrationReference.cs new file mode 100644 index 00000000000..b6d54013ce4 --- /dev/null +++ b/src/Aspire.Cli/Configuration/IntegrationReference.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Cli.Configuration; + +/// +/// Represents a reference to an Aspire hosting integration, which can be either +/// a NuGet package (with a version) or a local project reference (with a path to a .csproj). +/// Exactly one of or must be non-null. +/// +internal sealed class IntegrationReference +{ + /// + /// Gets the package or assembly name (e.g., "Aspire.Hosting.Redis"). + /// + public required string Name { get; init; } + + /// + /// Gets the NuGet package version, or null for project references. + /// + public string? Version { get; init; } + + /// + /// Gets the absolute path to the .csproj file, or null for NuGet packages. + /// + public string? ProjectPath { get; init; } + + /// + /// Returns true if this is a project reference (has a .csproj path). + /// + public bool IsProjectReference => ProjectPath is not null; + + /// + /// Returns true if this is a NuGet package reference (has a version). + /// + public bool IsPackageReference => Version is not null; + + /// + /// Creates a NuGet package reference. + /// + /// The package name. + /// The NuGet package version. + public static IntegrationReference FromPackage(string name, string version) + { + ArgumentException.ThrowIfNullOrEmpty(name); + ArgumentException.ThrowIfNullOrEmpty(version); + + return new IntegrationReference { Name = name, Version = version }; + } + + /// + /// Creates a local project reference. + /// + /// The assembly name. + /// The absolute path to the .csproj file. + public static IntegrationReference FromProject(string name, string projectPath) + { + ArgumentException.ThrowIfNullOrEmpty(name); + ArgumentException.ThrowIfNullOrEmpty(projectPath); + + return new IntegrationReference { Name = name, ProjectPath = projectPath }; + } +} diff --git a/src/Aspire.Cli/Mcp/Tools/ListConsoleLogsTool.cs b/src/Aspire.Cli/Mcp/Tools/ListConsoleLogsTool.cs index e5e2cc06975..b0813e8dfce 100644 --- a/src/Aspire.Cli/Mcp/Tools/ListConsoleLogsTool.cs +++ b/src/Aspire.Cli/Mcp/Tools/ListConsoleLogsTool.cs @@ -18,7 +18,7 @@ internal sealed class ListConsoleLogsTool(IAuxiliaryBackchannelMonitor auxiliary { public override string Name => KnownMcpTools.ListConsoleLogs; - public override string Description => "List console logs for a resource. The console logs includes standard output from resources and resource commands. Known resource commands are 'resource-start', 'resource-stop' and 'resource-restart' which are used to start and stop resources. Don't print the full console logs in the response to the user. Console logs should be examined when determining why a resource isn't running."; + public override string Description => "List console logs for a resource. The console logs includes standard output from resources and resource commands. Known resource commands are 'start', 'stop' and 'restart' which are used to start and stop resources. Don't print the full console logs in the response to the user. Console logs should be examined when determining why a resource isn't running."; public override JsonElement GetInputSchema() { diff --git a/src/Aspire.Cli/Program.cs b/src/Aspire.Cli/Program.cs index 1a52021b572..855e1679437 100644 --- a/src/Aspire.Cli/Program.cs +++ b/src/Aspire.Cli/Program.cs @@ -371,7 +371,6 @@ internal static async Task BuildApplicationAsync(string[] args, Dictionar builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); - builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); @@ -614,6 +613,9 @@ public static async Task Main(string[] args) try { + cliLogger.LogInformation("Version: {Version}", AspireCliTelemetry.GetCliVersion()); + cliLogger.LogInformation("Build ID: {BuildId}", AspireCliTelemetry.GetCliBuildId()); + // Log command invocation details for debugging var commandLine = args.Length > 0 ? $"aspire {string.Join(" ", args)}" : "aspire"; var workingDir = Environment.CurrentDirectory; diff --git a/src/Aspire.Cli/Projects/AppHostServerProject.cs b/src/Aspire.Cli/Projects/AppHostServerProject.cs index 8466bf77766..7e4a40d38bd 100644 --- a/src/Aspire.Cli/Projects/AppHostServerProject.cs +++ b/src/Aspire.Cli/Projects/AppHostServerProject.cs @@ -31,6 +31,7 @@ internal sealed class AppHostServerProjectFactory( IConfigurationService configurationService, IBundleService bundleService, BundleNuGetService bundleNuGetService, + IDotNetSdkInstaller sdkInstaller, ILoggerFactory loggerFactory) : IAppHostServerProjectFactory { public async Task CreateAsync(string appPath, CancellationToken cancellationToken = default) @@ -83,6 +84,8 @@ public async Task CreateAsync(string appPath, Cancellatio socketPath, layout, bundleNuGetService, + dotNetCliRunner, + sdkInstaller, packagingService, configurationService, loggerFactory.CreateLogger()); diff --git a/src/Aspire.Cli/Projects/AppHostServerSession.cs b/src/Aspire.Cli/Projects/AppHostServerSession.cs index 133181f30e1..e1376820cb0 100644 --- a/src/Aspire.Cli/Projects/AppHostServerSession.cs +++ b/src/Aspire.Cli/Projects/AppHostServerSession.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using Aspire.Cli.Configuration; using Aspire.Cli.Utils; using Microsoft.Extensions.Logging; @@ -100,7 +101,7 @@ public AppHostServerSessionFactory( public async Task CreateAsync( string appHostPath, string sdkVersion, - IEnumerable<(string PackageId, string Version)> packages, + IEnumerable integrations, Dictionary? launchSettingsEnvVars, bool debug, CancellationToken cancellationToken) @@ -108,7 +109,7 @@ public async Task CreateAsync( var appHostServerProject = await _projectFactory.CreateAsync(appHostPath, cancellationToken); // Prepare the server (create files + build for dev mode, restore packages for prebuilt mode) - var prepareResult = await appHostServerProject.PrepareAsync(sdkVersion, packages, cancellationToken); + var prepareResult = await appHostServerProject.PrepareAsync(sdkVersion, integrations, cancellationToken); if (!prepareResult.Success) { return new AppHostServerSessionResult( diff --git a/src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs b/src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs index 47b8dcbc09e..c0e96f8e839 100644 --- a/src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs +++ b/src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs @@ -26,7 +26,7 @@ internal sealed class DotNetBasedAppHostServerProject : IAppHostServerProject private const string AppsFolder = "hosts"; public const string ProjectFileName = "AppHostServer.csproj"; private const string ProjectDllName = "AppHostServer.dll"; - private const string TargetFramework = "net10.0"; + internal const string TargetFramework = "net10.0"; public const string BuildFolder = "build"; private const string AssemblyName = "AppHostServer"; @@ -135,7 +135,7 @@ public void SaveProjectHash(string hash) /// /// Creates the project .csproj content using project references to the local Aspire repository. /// - private XDocument CreateProjectFile(IEnumerable<(string Name, string Version)> packages) + private XDocument CreateProjectFile(IEnumerable integrations) { // Determine OS/architecture for DCP package name var (buildOs, buildArch) = GetBuildPlatform(); @@ -183,12 +183,22 @@ private XDocument CreateProjectFile(IEnumerable<(string Name, string Version)> p var addedProjects = new HashSet(StringComparer.OrdinalIgnoreCase); var otherPackages = new List<(string Name, string Version)>(); - foreach (var (name, version) in packages) + foreach (var integration in integrations) { - if (name.StartsWith("Aspire.Hosting", StringComparison.OrdinalIgnoreCase)) + if (integration.IsProjectReference) { - var projectPath = Path.Combine(_repoRoot, "src", name, $"{name}.csproj"); - if (File.Exists(projectPath) && addedProjects.Add(name)) + // Explicit project reference from settings.json + if (addedProjects.Add(integration.Name)) + { + projectRefGroup.Add(new XElement("ProjectReference", + new XAttribute("Include", integration.ProjectPath!), + new XElement("IsAspireProjectResource", "false"))); + } + } + else if (integration.Name.StartsWith("Aspire.Hosting", StringComparison.OrdinalIgnoreCase)) + { + var projectPath = Path.Combine(_repoRoot, "src", integration.Name, $"{integration.Name}.csproj"); + if (File.Exists(projectPath) && addedProjects.Add(integration.Name)) { projectRefGroup.Add(new XElement("ProjectReference", new XAttribute("Include", projectPath), @@ -197,7 +207,11 @@ private XDocument CreateProjectFile(IEnumerable<(string Name, string Version)> p } else { - otherPackages.Add((name, version)); + if (integration.Version is null) + { + throw new InvalidOperationException($"Integration '{integration.Name}' is neither a project reference nor a package reference (both Version and ProjectPath are null)."); + } + otherPackages.Add((integration.Name, integration.Version)); } } @@ -262,9 +276,8 @@ private XDocument CreateProjectFile(IEnumerable<(string Name, string Version)> p /// Scaffolds the project files. /// public async Task<(string ProjectPath, string? ChannelName)> CreateProjectFilesAsync( - IEnumerable<(string Name, string Version)> packages, - CancellationToken cancellationToken = default, - IEnumerable? additionalProjectReferences = null) + IEnumerable integrations, + CancellationToken cancellationToken = default) { // Clean obj folder to ensure fresh NuGet restore var objPath = Path.Combine(_projectModelPath, "obj"); @@ -288,23 +301,18 @@ private XDocument CreateProjectFile(IEnumerable<(string Name, string Version)> p // Create appsettings.json with ATS assemblies var atsAssemblies = new List { "Aspire.Hosting" }; - foreach (var pkg in packages) + foreach (var integration in integrations) { - if (!atsAssemblies.Contains(pkg.Name, StringComparer.OrdinalIgnoreCase)) + // Skip SDK-only packages that don't produce runtime assemblies + if (integration.Name.Equals("Aspire.Hosting.AppHost", StringComparison.OrdinalIgnoreCase) || + integration.Name.StartsWith("Aspire.AppHost.Sdk", StringComparison.OrdinalIgnoreCase)) { - atsAssemblies.Add(pkg.Name); + continue; } - } - if (additionalProjectReferences is not null) - { - foreach (var projectPath in additionalProjectReferences) + if (!atsAssemblies.Contains(integration.Name, StringComparer.OrdinalIgnoreCase)) { - var assemblyName = Path.GetFileNameWithoutExtension(projectPath); - if (!atsAssemblies.Contains(assemblyName, StringComparer.OrdinalIgnoreCase)) - { - atsAssemblies.Add(assemblyName); - } + atsAssemblies.Add(integration.Name); } } @@ -327,11 +335,11 @@ private XDocument CreateProjectFile(IEnumerable<(string Name, string Version)> p // Handle NuGet config and channel resolution string? channelName = null; - var nugetConfigPath = Path.Combine(_projectModelPath, "nuget.config"); var userNugetConfig = FindNuGetConfig(_appPath); if (userNugetConfig is not null) { + var nugetConfigPath = Path.Combine(_projectModelPath, "nuget.config"); File.Copy(userNugetConfig, nugetConfigPath, overwrite: true); } @@ -344,41 +352,37 @@ private XDocument CreateProjectFile(IEnumerable<(string Name, string Version)> p configuredChannelName = await _configurationService.GetConfigurationAsync("channel", cancellationToken); } - PackageChannel? channel; - if (!string.IsNullOrEmpty(configuredChannelName)) - { - channel = channels.FirstOrDefault(c => string.Equals(c.Name, configuredChannelName, StringComparison.OrdinalIgnoreCase)); - } - else - { - channel = channels.FirstOrDefault(c => c.Type == PackageChannelType.Explicit); - } + // Resolve channel sources and add them via RestoreAdditionalProjectSources + // This is additive — it preserves the user's nuget.config and adds channel-specific sources + var channelSources = new List(); + var matchedChannels = !string.IsNullOrEmpty(configuredChannelName) + ? channels.Where(c => string.Equals(c.Name, configuredChannelName, StringComparison.OrdinalIgnoreCase)) + : channels.Where(c => c.Type == PackageChannelType.Explicit); - if (channel is not null) + foreach (var ch in matchedChannels) { - await NuGetConfigMerger.CreateOrUpdateAsync( - new DirectoryInfo(_projectModelPath), - channel, - cancellationToken: cancellationToken); - channelName = channel.Name; + channelName ??= ch.Name; + if (ch.Mappings is not null) + { + foreach (var mapping in ch.Mappings) + { + if (!channelSources.Contains(mapping.Source, StringComparer.OrdinalIgnoreCase)) + { + channelSources.Add(mapping.Source); + } + } + } } // Create the project file - var doc = CreateProjectFile(packages); + var doc = CreateProjectFile(integrations); - // Add additional project references - if (additionalProjectReferences is not null) + // Add channel sources to the project so project references can resolve packages + if (channelSources.Count > 0) { - var additionalProjectRefs = additionalProjectReferences - .Select(path => new XElement("ProjectReference", - new XAttribute("Include", path), - new XElement("IsAspireProjectResource", "false"))) - .ToList(); - - if (additionalProjectRefs.Count > 0) - { - doc.Root!.Add(new XElement("ItemGroup", additionalProjectRefs)); - } + var sourceList = string.Join(";", channelSources); + doc.Root!.Descendants("PropertyGroup").First() + .Add(new XElement("RestoreAdditionalProjectSources", sourceList)); } // Add appsettings.json to output @@ -433,10 +437,10 @@ await NuGetConfigMerger.CreateOrUpdateAsync( /// public async Task PrepareAsync( string sdkVersion, - IEnumerable<(string Name, string Version)> packages, + IEnumerable integrations, CancellationToken cancellationToken = default) { - var (_, channelName) = await CreateProjectFilesAsync(packages, cancellationToken); + var (_, channelName) = await CreateProjectFilesAsync(integrations, cancellationToken); var (buildSuccess, buildOutput) = await BuildAsync(cancellationToken); if (!buildSuccess) diff --git a/src/Aspire.Cli/Projects/GuestAppHostProject.cs b/src/Aspire.Cli/Projects/GuestAppHostProject.cs index be59f437027..b2f9b4c764d 100644 --- a/src/Aspire.Cli/Projects/GuestAppHostProject.cs +++ b/src/Aspire.Cli/Projects/GuestAppHostProject.cs @@ -137,21 +137,22 @@ public bool IsUsingProjectReferences(FileInfo appHostFile) } /// - /// Gets all packages including the code generation package for the current language. + /// Gets all integration references including the code generation package for the current language. /// - private async Task> GetAllPackagesAsync( + private async Task> GetIntegrationReferencesAsync( AspireJsonConfiguration config, + DirectoryInfo directory, CancellationToken cancellationToken) { var defaultSdkVersion = GetEffectiveSdkVersion(); - var packages = config.GetAllPackages(defaultSdkVersion).ToList(); + var integrations = config.GetIntegrationReferences(defaultSdkVersion, directory.FullName).ToList(); var codeGenPackage = await _languageDiscovery.GetPackageForLanguageAsync(_resolvedLanguage.LanguageId, cancellationToken); if (codeGenPackage is not null) { var codeGenVersion = config.GetEffectiveSdkVersion(defaultSdkVersion); - packages.Add((codeGenPackage, codeGenVersion)); + integrations.Add(IntegrationReference.FromPackage(codeGenPackage, codeGenVersion)); } - return packages; + return integrations; } private AspireJsonConfiguration LoadConfiguration(DirectoryInfo directory) @@ -171,10 +172,10 @@ private string GetPrepareSdkVersion(AspireJsonConfiguration config) private static async Task<(bool Success, OutputCollector? Output, string? ChannelName, bool NeedsCodeGen)> PrepareAppHostServerAsync( IAppHostServerProject appHostServerProject, string sdkVersion, - List<(string Name, string Version)> packages, + List integrations, CancellationToken cancellationToken) { - var result = await appHostServerProject.PrepareAsync(sdkVersion, packages, cancellationToken); + var result = await appHostServerProject.PrepareAsync(sdkVersion, integrations, cancellationToken); return (result.Success, result.Output, result.ChannelName, result.NeedsCodeGeneration); } @@ -187,10 +188,10 @@ private async Task BuildAndGenerateSdkAsync(DirectoryInfo directory, Cancellatio // Step 1: Load config - source of truth for SDK version and packages var config = LoadConfiguration(directory); - var packages = await GetAllPackagesAsync(config, cancellationToken); + var integrations = await GetIntegrationReferencesAsync(config, directory, cancellationToken); var sdkVersion = GetPrepareSdkVersion(config); - var (buildSuccess, buildOutput, _, _) = await PrepareAppHostServerAsync(appHostServerProject, sdkVersion, packages, cancellationToken); + var (buildSuccess, buildOutput, _, _) = await PrepareAppHostServerAsync(appHostServerProject, sdkVersion, integrations, cancellationToken); if (!buildSuccess) { if (buildOutput is not null) @@ -217,7 +218,7 @@ private async Task BuildAndGenerateSdkAsync(DirectoryInfo directory, Cancellatio await GenerateCodeViaRpcAsync( directory.FullName, rpcClient, - packages, + integrations, cancellationToken); } finally @@ -294,7 +295,7 @@ public async Task RunAsync(AppHostProjectContext context, CancellationToken // Load config - source of truth for SDK version and packages var config = LoadConfiguration(directory); - var packages = await GetAllPackagesAsync(config, cancellationToken); + var integrations = await GetIntegrationReferencesAsync(config, directory, cancellationToken); var sdkVersion = GetPrepareSdkVersion(config); var buildResult = await _interactionService.ShowStatusAsync( @@ -302,7 +303,7 @@ public async Task RunAsync(AppHostProjectContext context, CancellationToken async () => { // Prepare the AppHost server (build for dev mode, restore for prebuilt) - var (prepareSuccess, prepareOutput, channelName, needsCodeGen) = await PrepareAppHostServerAsync(appHostServerProject, sdkVersion, packages, cancellationToken); + var (prepareSuccess, prepareOutput, channelName, needsCodeGen) = await PrepareAppHostServerAsync(appHostServerProject, sdkVersion, integrations, cancellationToken); if (!prepareSuccess) { return (Success: false, Output: prepareOutput, Error: "Failed to prepare app host.", ChannelName: (string?)null, NeedsCodeGen: false); @@ -407,7 +408,7 @@ public async Task RunAsync(AppHostProjectContext context, CancellationToken await GenerateCodeViaRpcAsync( directory.FullName, rpcClient, - packages, + integrations, cancellationToken); } @@ -598,11 +599,11 @@ public async Task PublishAsync(PublishContext context, CancellationToken ca // Step 1: Load config - source of truth for SDK version and packages var appHostServerProject = await _appHostServerProjectFactory.CreateAsync(directory.FullName, cancellationToken); var config = LoadConfiguration(directory); - var packages = await GetAllPackagesAsync(config, cancellationToken); + var integrations = await GetIntegrationReferencesAsync(config, directory, cancellationToken); var sdkVersion = GetPrepareSdkVersion(config); // Prepare the AppHost server (build for dev mode, restore for prebuilt) - var (prepareSuccess, prepareOutput, _, needsCodeGen) = await PrepareAppHostServerAsync(appHostServerProject, sdkVersion, packages, cancellationToken); + var (prepareSuccess, prepareOutput, _, needsCodeGen) = await PrepareAppHostServerAsync(appHostServerProject, sdkVersion, integrations, cancellationToken); if (!prepareSuccess) { // Set OutputCollector so PipelineCommandBase can display errors @@ -680,7 +681,7 @@ public async Task PublishAsync(PublishContext context, CancellationToken ca await GenerateCodeViaRpcAsync( directory.FullName, rpcClient, - packages, + integrations, cancellationToken); } @@ -1016,16 +1017,16 @@ public async Task FindAndStopRunningInstanceAsync(FileInf private async Task GenerateCodeViaRpcAsync( string appPath, IAppHostRpcClient rpcClient, - IEnumerable<(string PackageId, string Version)> packages, + IEnumerable integrations, CancellationToken cancellationToken) { - var packagesList = packages.ToList(); + var integrationsList = integrations.ToList(); // Use CodeGenerator (e.g., "TypeScript") not LanguageId (e.g., "typescript/nodejs") // The code generator is registered by its Language property, not the runtime ID var codeGenerator = _resolvedLanguage.CodeGenerator; - _logger.LogDebug("Generating {CodeGenerator} code via RPC for {Count} packages", codeGenerator, packagesList.Count); + _logger.LogDebug("Generating {CodeGenerator} code via RPC for {Count} packages", codeGenerator, integrationsList.Count); // Use the typed RPC method var files = await rpcClient.GenerateCodeAsync(codeGenerator, cancellationToken); @@ -1046,35 +1047,47 @@ private async Task GenerateCodeViaRpcAsync( } // Write generation hash for caching - SaveGenerationHash(outputPath, packagesList); + SaveGenerationHash(outputPath, integrationsList); _logger.LogInformation("Generated {Count} {CodeGenerator} files in {Path}", files.Count, codeGenerator, outputPath); } /// - /// Saves a hash of the packages to avoid regenerating code unnecessarily. + /// Saves a hash of the integrations to avoid regenerating code unnecessarily. + /// When project references are present, the hash is always unique to force regeneration + /// since project outputs are mutable. /// - private static void SaveGenerationHash(string generatedPath, List<(string PackageId, string Version)> packages) + private static void SaveGenerationHash(string generatedPath, List integrations) { var hashPath = Path.Combine(generatedPath, ".codegen-hash"); - var hash = ComputePackagesHash(packages); + var hash = ComputeIntegrationsHash(integrations); File.WriteAllText(hashPath, hash); } /// - /// Computes a hash of the package list for caching purposes. + /// Computes a hash of the integration list for caching purposes. + /// If any project references are present, includes a timestamp to force regeneration + /// since project outputs can change between builds. /// - private static string ComputePackagesHash(List<(string PackageId, string Version)> packages) + private static string ComputeIntegrationsHash(List integrations) { var sb = new System.Text.StringBuilder(); - foreach (var (packageId, version) in packages.OrderBy(p => p.PackageId)) + foreach (var integration in integrations.OrderBy(p => p.Name)) { - sb.Append(packageId); + sb.Append(integration.Name); sb.Append(':'); - sb.Append(version); + sb.Append(integration.Version ?? integration.ProjectPath ?? ""); sb.Append(';'); } + + // Project references are mutable — always regenerate when they're present + if (integrations.Any(i => i.IsProjectReference)) + { + sb.Append("timestamp:"); + sb.Append(DateTime.UtcNow.Ticks); + } + var bytes = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(sb.ToString())); return Convert.ToHexString(bytes); } diff --git a/src/Aspire.Cli/Projects/IAppHostServerProject.cs b/src/Aspire.Cli/Projects/IAppHostServerProject.cs index 351dc2402af..8c19179b308 100644 --- a/src/Aspire.Cli/Projects/IAppHostServerProject.cs +++ b/src/Aspire.Cli/Projects/IAppHostServerProject.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using Aspire.Cli.Configuration; using Aspire.Cli.Utils; namespace Aspire.Cli.Projects; @@ -38,12 +39,12 @@ internal interface IAppHostServerProject /// For bundle mode: restores integration packages from NuGet. /// /// The Aspire SDK version to use. - /// The integration packages required by the app host. + /// The integration references (NuGet packages and/or project references) required by the app host. /// Cancellation token. /// The preparation result indicating success/failure and any output. Task PrepareAsync( string sdkVersion, - IEnumerable<(string Name, string Version)> packages, + IEnumerable integrations, CancellationToken cancellationToken = default); /// diff --git a/src/Aspire.Cli/Projects/IAppHostServerSession.cs b/src/Aspire.Cli/Projects/IAppHostServerSession.cs index 843ad10b97c..8668a92796c 100644 --- a/src/Aspire.Cli/Projects/IAppHostServerSession.cs +++ b/src/Aspire.Cli/Projects/IAppHostServerSession.cs @@ -4,6 +4,8 @@ using System.Diagnostics; using Aspire.Cli.Utils; +using Aspire.Cli.Configuration; + namespace Aspire.Cli.Projects; /// @@ -43,7 +45,7 @@ internal interface IAppHostServerSessionFactory /// /// The path to the AppHost project directory. /// The Aspire SDK version to use. - /// The package references to include. + /// The integration references to include. /// Optional environment variables from launch settings. /// Whether to enable debug logging. /// Cancellation token. @@ -51,7 +53,7 @@ internal interface IAppHostServerSessionFactory Task CreateAsync( string appHostPath, string sdkVersion, - IEnumerable<(string PackageId, string Version)> packages, + IEnumerable integrations, Dictionary? launchSettingsEnvVars, bool debug, CancellationToken cancellationToken); diff --git a/src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs b/src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs index 2a0c1c8c0d3..ed3d1d63dce 100644 --- a/src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs +++ b/src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs @@ -4,7 +4,9 @@ using System.Diagnostics; using System.Security.Cryptography; using System.Text; +using System.Xml.Linq; using Aspire.Cli.Configuration; +using Aspire.Cli.DotNet; using Aspire.Cli.Layout; using Aspire.Cli.NuGet; using Aspire.Cli.Packaging; @@ -26,6 +28,8 @@ internal sealed class PrebuiltAppHostServer : IAppHostServerProject private readonly string _socketPath; private readonly LayoutConfiguration _layout; private readonly BundleNuGetService _nugetService; + private readonly IDotNetCliRunner _dotNetCliRunner; + private readonly IDotNetSdkInstaller _sdkInstaller; private readonly IPackagingService _packagingService; private readonly IConfigurationService _configurationService; private readonly ILogger _logger; @@ -37,10 +41,12 @@ internal sealed class PrebuiltAppHostServer : IAppHostServerProject /// /// Initializes a new instance of the PrebuiltAppHostServer class. /// - /// The path to the user's polyglot app host. + /// The path to the user's polyglot app host directory. /// The socket path for JSON-RPC communication. /// The bundle layout configuration. - /// The NuGet service for restoring integration packages. + /// The NuGet service for restoring integration packages (NuGet-only path). + /// The .NET CLI runner for building project references. + /// The SDK installer for checking .NET SDK availability. /// The packaging service for channel resolution. /// The configuration service for reading channel settings. /// The logger for diagnostic output. @@ -49,6 +55,8 @@ public PrebuiltAppHostServer( string socketPath, LayoutConfiguration layout, BundleNuGetService nugetService, + IDotNetCliRunner dotNetCliRunner, + IDotNetSdkInstaller sdkInstaller, IPackagingService packagingService, IConfigurationService configurationService, ILogger logger) @@ -57,6 +65,8 @@ public PrebuiltAppHostServer( _socketPath = socketPath; _layout = layout; _nugetService = nugetService; + _dotNetCliRunner = dotNetCliRunner; + _sdkInstaller = sdkInstaller; _packagingService = packagingService; _configurationService = configurationService; _logger = logger; @@ -88,37 +98,46 @@ public string GetServerPath() /// public async Task PrepareAsync( string sdkVersion, - IEnumerable<(string Name, string Version)> packages, + IEnumerable integrations, CancellationToken cancellationToken = default) { - var packageList = packages.ToList(); + var integrationList = integrations.ToList(); + var packageRefs = integrationList.Where(r => r.IsPackageReference).ToList(); + var projectRefs = integrationList.Where(r => r.IsProjectReference).ToList(); try { - // Generate appsettings.json with ATS assemblies for the server to scan - await GenerateAppSettingsAsync(packageList, cancellationToken); - // Resolve the configured channel (local settings.json → global config fallback) var channelName = await ResolveChannelNameAsync(cancellationToken); - // Restore integration packages - if (packageList.Count > 0) + if (projectRefs.Count > 0) { - _logger.LogDebug("Restoring {Count} integration packages", packageList.Count); - - // Get NuGet sources filtered to the resolved channel - var sources = await GetNuGetSourcesAsync(channelName, cancellationToken); - - // Pass apphost directory for nuget.config discovery - var appHostDirectory = Path.GetDirectoryName(_appPath); + // Project references require .NET SDK — verify it's available + var (sdkAvailable, _, minimumRequired) = await _sdkInstaller.CheckAsync(cancellationToken); + if (!sdkAvailable) + { + throw new InvalidOperationException( + $"Project references in settings.json require .NET SDK {minimumRequired} or later. " + + "Install the .NET SDK from https://dotnet.microsoft.com/download or use NuGet package versions instead."); + } - _integrationLibsPath = await _nugetService.RestorePackagesAsync( - packageList, - "net10.0", - sources: sources, - workingDirectory: appHostDirectory, - ct: cancellationToken); + // Build a synthetic project with all package and project references + _integrationLibsPath = await BuildIntegrationProjectAsync( + packageRefs, projectRefs, channelName, cancellationToken); } + else if (packageRefs.Count > 0) + { + // NuGet-only — use the bundled NuGet service (no SDK required) + _integrationLibsPath = await RestoreNuGetPackagesAsync( + packageRefs, channelName, cancellationToken); + } + + // Generate appsettings.json after build/restore so we can use actual assembly names + // from the build output (project references may have custom ) + var projectRefAssemblyNames = _integrationLibsPath is not null + ? await ReadProjectRefAssemblyNamesAsync(_integrationLibsPath, cancellationToken) + : []; + await GenerateAppSettingsAsync(packageRefs, projectRefAssemblyNames, cancellationToken); return new AppHostServerPrepareResult( Success: true, @@ -139,6 +158,178 @@ public async Task PrepareAsync( } } + /// + /// Restores NuGet packages using the bundled NuGet service (no .NET SDK required). + /// + private async Task RestoreNuGetPackagesAsync( + List packageRefs, + string? channelName, + CancellationToken cancellationToken) + { + _logger.LogDebug("Restoring {Count} integration packages via bundled NuGet", packageRefs.Count); + + var packages = packageRefs.Select(r => (r.Name, r.Version!)).ToList(); + var sources = await GetNuGetSourcesAsync(channelName, cancellationToken); + var appHostDirectory = Path.GetDirectoryName(_appPath); + + return await _nugetService.RestorePackagesAsync( + packages, + DotNetBasedAppHostServerProject.TargetFramework, + sources: sources, + workingDirectory: appHostDirectory, + ct: cancellationToken); + } + + /// + /// Creates a synthetic .csproj with all package and project references, + /// then builds it to get the full transitive DLL closure via CopyLocalLockFileAssemblies. + /// Requires .NET SDK. + /// + private async Task BuildIntegrationProjectAsync( + List packageRefs, + List projectRefs, + string? channelName, + CancellationToken cancellationToken) + { + var restoreDir = Path.Combine(_workingDirectory, "integration-restore"); + Directory.CreateDirectory(restoreDir); + + var outputDir = Path.Combine(restoreDir, "libs"); + // Clean stale DLLs from previous builds to prevent leftover assemblies + // from removed integrations being picked up by the assembly resolver + if (Directory.Exists(outputDir)) + { + Directory.Delete(outputDir, recursive: true); + } + Directory.CreateDirectory(outputDir); + + // Resolve channel sources to add via RestoreAdditionalProjectSources + IEnumerable? channelSources = null; + try + { + channelSources = await GetNuGetSourcesAsync(channelName, cancellationToken); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to configure NuGet sources for integration project build"); + } + + var projectContent = GenerateIntegrationProjectFile(packageRefs, projectRefs, outputDir, channelSources); + var projectFilePath = Path.Combine(restoreDir, "IntegrationRestore.csproj"); + await File.WriteAllTextAsync(projectFilePath, projectContent, cancellationToken); + + // Write a Directory.Packages.props to opt out of Central Package Management + var directoryPackagesProps = """ + + + false + + + """; + await File.WriteAllTextAsync( + Path.Combine(restoreDir, "Directory.Packages.props"), directoryPackagesProps, cancellationToken); + + // Also write an empty Directory.Build.props/targets to prevent parent imports + await File.WriteAllTextAsync( + Path.Combine(restoreDir, "Directory.Build.props"), "", cancellationToken); + await File.WriteAllTextAsync( + Path.Combine(restoreDir, "Directory.Build.targets"), "", cancellationToken); + + _logger.LogDebug("Building integration project with {PackageCount} packages and {ProjectCount} project references", + packageRefs.Count, projectRefs.Count); + + var buildOutput = new OutputCollector(); + var exitCode = await _dotNetCliRunner.BuildAsync( + new FileInfo(projectFilePath), + noRestore: false, + new DotNetCliRunnerInvocationOptions + { + StandardOutputCallback = buildOutput.AppendOutput, + StandardErrorCallback = buildOutput.AppendError + }, + cancellationToken); + + if (exitCode != 0) + { + var outputLines = string.Join(Environment.NewLine, buildOutput.GetLines().Select(l => l.Line)); + _logger.LogError("Integration project build failed. Output:\n{BuildOutput}", outputLines); + throw new InvalidOperationException($"Failed to build integration project. Exit code: {exitCode}"); + } + + return outputDir; + } + + /// + /// Generates a synthetic .csproj file that references all integration packages and projects. + /// Building this project with CopyLocalLockFileAssemblies produces the full transitive DLL closure. + /// + internal static string GenerateIntegrationProjectFile( + List packageRefs, + List projectRefs, + string outputDir, + IEnumerable? additionalSources = null) + { + var propertyGroup = new XElement("PropertyGroup", + new XElement("TargetFramework", DotNetBasedAppHostServerProject.TargetFramework), + new XElement("EnableDefaultItems", "false"), + new XElement("CopyLocalLockFileAssemblies", "true"), + new XElement("ProduceReferenceAssembly", "false"), + new XElement("EnableNETAnalyzers", "false"), + new XElement("GenerateDocumentationFile", "false"), + new XElement("OutDir", outputDir)); + + // Add channel sources without replacing the user's nuget.config + if (additionalSources is not null) + { + var sourceList = string.Join(";", additionalSources); + if (sourceList.Length > 0) + { + propertyGroup.Add(new XElement("RestoreAdditionalProjectSources", sourceList)); + } + } + + var doc = new XDocument( + new XElement("Project", + new XAttribute("Sdk", "Microsoft.NET.Sdk"), + propertyGroup)); + + if (packageRefs.Count > 0) + { + doc.Root!.Add(new XElement("ItemGroup", + packageRefs.Select(p => + { + if (p.Version is null) + { + throw new InvalidOperationException($"Package reference '{p.Name}' is missing a version."); + } + return new XElement("PackageReference", + new XAttribute("Include", p.Name), + new XAttribute("Version", p.Version)); + }))); + } + + if (projectRefs.Count > 0) + { + doc.Root!.Add(new XElement("ItemGroup", + projectRefs.Select(p => new XElement("ProjectReference", + new XAttribute("Include", p.ProjectPath!))))); + + // Add a target that writes the resolved project reference assembly names to a file. + // This lets us discover the actual assembly names after build (which may differ from + // the settings.json key or csproj filename if is overridden). + doc.Root!.Add( + new XElement("Target", + new XAttribute("Name", "_WriteProjectRefAssemblyNames"), + new XAttribute("AfterTargets", "Build"), + new XElement("WriteLinesToFile", + new XAttribute("File", Path.Combine(outputDir, "_project-ref-assemblies.txt")), + new XAttribute("Lines", "@(_ResolvedProjectReferencePaths->'%(Filename)')"), + new XAttribute("Overwrite", "true")))); + } + + return doc.ToString(); + } + /// /// Resolves the configured channel name from local settings.json or global config. /// @@ -163,7 +354,7 @@ public async Task PrepareAsync( } /// - /// Gets NuGet sources from the resolved channel, or all explicit channels if no channel is configured. + /// Gets NuGet sources from the resolved channel for bundled restore. /// private async Task?> GetNuGetSourcesAsync(string? channelName, CancellationToken cancellationToken) { @@ -176,13 +367,11 @@ public async Task PrepareAsync( IEnumerable explicitChannels; if (!string.IsNullOrEmpty(channelName)) { - // Filter to the configured channel var matchingChannel = channels.FirstOrDefault(c => string.Equals(c.Name, channelName, StringComparison.OrdinalIgnoreCase)); explicitChannels = matchingChannel is not null ? [matchingChannel] : channels.Where(c => c.Type == PackageChannelType.Explicit); } else { - // No channel configured, use all explicit channels explicitChannels = channels.Where(c => c.Type == PackageChannelType.Explicit); } @@ -198,7 +387,6 @@ public async Task PrepareAsync( if (!sources.Contains(mapping.Source, StringComparer.OrdinalIgnoreCase)) { sources.Add(mapping.Source); - _logger.LogDebug("Using channel '{Channel}' NuGet source: {Source}", channel.Name, mapping.Source); } } } @@ -319,22 +507,45 @@ public async Task PrepareAsync( /// public string GetInstanceIdentifier() => _appPath; + /// + /// Reads the project reference assembly names written by the MSBuild target during build. + /// + private async Task> ReadProjectRefAssemblyNamesAsync(string libsPath, CancellationToken cancellationToken) + { + var filePath = Path.Combine(libsPath, "_project-ref-assemblies.txt"); + if (!File.Exists(filePath)) + { + _logger.LogWarning("Project reference assembly names file not found at {Path}", filePath); + return []; + } + + var lines = await File.ReadAllLinesAsync(filePath, cancellationToken); + return lines.Where(l => !string.IsNullOrWhiteSpace(l)).Select(l => l.Trim()).ToList(); + } + private async Task GenerateAppSettingsAsync( - List<(string Name, string Version)> packages, + List packageRefs, + List projectRefAssemblyNames, CancellationToken cancellationToken) { - // Build the list of ATS assemblies (for [AspireExport] scanning) - // Skip SDK-only packages that don't have runtime DLLs var atsAssemblies = new List { "Aspire.Hosting" }; - foreach (var (name, _) in packages) + + foreach (var pkg in packageRefs) { - // Skip SDK packages that don't produce runtime assemblies - if (name.Equals("Aspire.Hosting.AppHost", StringComparison.OrdinalIgnoreCase) || - name.StartsWith("Aspire.AppHost.Sdk", StringComparison.OrdinalIgnoreCase)) + if (pkg.Name.Equals("Aspire.Hosting.AppHost", StringComparison.OrdinalIgnoreCase) || + pkg.Name.StartsWith("Aspire.AppHost.Sdk", StringComparison.OrdinalIgnoreCase)) { continue; } + if (!atsAssemblies.Contains(pkg.Name, StringComparer.OrdinalIgnoreCase)) + { + atsAssemblies.Add(pkg.Name); + } + } + + foreach (var name in projectRefAssemblyNames) + { if (!atsAssemblies.Contains(name, StringComparer.OrdinalIgnoreCase)) { atsAssemblies.Add(name); diff --git a/src/Aspire.Cli/Resources/ResourceCommandStrings.Designer.cs b/src/Aspire.Cli/Resources/ResourceCommandStrings.Designer.cs index cf4c27677f3..a8b53222983 100644 --- a/src/Aspire.Cli/Resources/ResourceCommandStrings.Designer.cs +++ b/src/Aspire.Cli/Resources/ResourceCommandStrings.Designer.cs @@ -51,30 +51,6 @@ internal static string SelectAppHostAction { } } - internal static string StartDescription { - get { - return ResourceManager.GetString("StartDescription", resourceCulture); - } - } - - internal static string StartResourceArgumentDescription { - get { - return ResourceManager.GetString("StartResourceArgumentDescription", resourceCulture); - } - } - - internal static string RestartDescription { - get { - return ResourceManager.GetString("RestartDescription", resourceCulture); - } - } - - internal static string RestartResourceArgumentDescription { - get { - return ResourceManager.GetString("RestartResourceArgumentDescription", resourceCulture); - } - } - internal static string CommandDescription { get { return ResourceManager.GetString("CommandDescription", resourceCulture); @@ -93,10 +69,5 @@ internal static string CommandNameArgumentDescription { } } - internal static string OptionNotValidWithResource { - get { - return ResourceManager.GetString("OptionNotValidWithResource", resourceCulture); - } - } } } diff --git a/src/Aspire.Cli/Resources/ResourceCommandStrings.resx b/src/Aspire.Cli/Resources/ResourceCommandStrings.resx index 12004c39c05..cc889718167 100644 --- a/src/Aspire.Cli/Resources/ResourceCommandStrings.resx +++ b/src/Aspire.Cli/Resources/ResourceCommandStrings.resx @@ -61,28 +61,13 @@ connect to - - Start an apphost in the background, or start a stopped resource. - - - The name of the resource to start. If not specified, starts the AppHost in the background. - - - Restart a running resource. - - - The name of the resource to restart. - - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). The name of the resource to execute the command on. - The name of the command to execute. - - - The '{0}' option is not valid when starting a resource. + The name of the command to execute (e.g. start, stop, restart). diff --git a/src/Aspire.Cli/Resources/StartCommandStrings.Designer.cs b/src/Aspire.Cli/Resources/StartCommandStrings.Designer.cs new file mode 100644 index 00000000000..3c9d761e05f --- /dev/null +++ b/src/Aspire.Cli/Resources/StartCommandStrings.Designer.cs @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aspire.Cli.Resources { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class StartCommandStrings { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal StartCommandStrings() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Cli.Resources.StartCommandStrings", typeof(StartCommandStrings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static string Description { + get { + return ResourceManager.GetString("Description", resourceCulture); + } + } + + } +} diff --git a/src/Aspire.Cli/Resources/StartCommandStrings.resx b/src/Aspire.Cli/Resources/StartCommandStrings.resx new file mode 100644 index 00000000000..adc1fd53064 --- /dev/null +++ b/src/Aspire.Cli/Resources/StartCommandStrings.resx @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Start an apphost in the background. + + diff --git a/src/Aspire.Cli/Resources/StopCommandStrings.Designer.cs b/src/Aspire.Cli/Resources/StopCommandStrings.Designer.cs index c4e6da1a2d1..453094bd7bf 100644 --- a/src/Aspire.Cli/Resources/StopCommandStrings.Designer.cs +++ b/src/Aspire.Cli/Resources/StopCommandStrings.Designer.cs @@ -105,10 +105,5 @@ public static string AllAndProjectMutuallyExclusive { } } - public static string AllAndResourceMutuallyExclusive { - get { - return ResourceManager.GetString("AllAndResourceMutuallyExclusive", resourceCulture); - } - } } } diff --git a/src/Aspire.Cli/Resources/StopCommandStrings.resx b/src/Aspire.Cli/Resources/StopCommandStrings.resx index 77ab8659ac2..ac2fed6a225 100644 --- a/src/Aspire.Cli/Resources/StopCommandStrings.resx +++ b/src/Aspire.Cli/Resources/StopCommandStrings.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Stop a running apphost or the specified resource. + Stop a running apphost. The path to the Aspire AppHost project file. @@ -147,7 +147,4 @@ The {0} and {1} options cannot be used together. - - The {0} option cannot be used with a resource argument. - diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.cs.xlf index d01a1770348..bad5039cdca 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.cs.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Spusťte příkaz pro prostředek. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Název příkazu, který se má spustit @@ -17,36 +17,11 @@ Název prostředku, na kterém se má příkaz provést - - The '{0}' option is not valid when starting a resource. - Možnost {0} není při spouštění prostředku platná. - - - - Restart a running resource. - Restartujte spuštěný prostředek. - - - - The name of the resource to restart. - Název prostředku, který se má restartovat - - connect to připojit k - - Start an apphost in the background, or start a stopped resource. - Spusťte hostitele aplikace na pozadí nebo spusťte zastavený prostředek. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Název prostředku, který se má spustit Pokud se nezadá, spustí AppHost na pozadí. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.de.xlf index fb3e77f4f9f..c5863d5733c 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.de.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Führen Sie einen Befehl auf einer Ressource aus. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Der Name des auszuführenden Befehls. @@ -17,36 +17,11 @@ Der Name der Ressource, für die der Befehl ausgeführt werden soll. - - The '{0}' option is not valid when starting a resource. - Die Option „{0}“ ist beim Starten einer Ressource nicht gültig. - - - - Restart a running resource. - Starten Sie eine laufende Ressource neu. - - - - The name of the resource to restart. - Der Name der Ressource, die neu gestartet werden soll. - - connect to stellen Sie eine Verbindung her mit - - Start an apphost in the background, or start a stopped resource. - Einen AppHost im Hintergrund starten oder eine gestoppte Ressource starten. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Der Name der Ressource, die gestartet werden soll. Wird kein Name angegeben, startet der AppHost im Hintergrund. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.es.xlf index 9b51ec92085..f3e1b865149 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.es.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Ejecute un comando en un recurso. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Nombre del comando que se va a ejecutar. @@ -17,36 +17,11 @@ El nombre del recurso de destino en el que se ejecutará el comando. - - The '{0}' option is not valid when starting a resource. - La opción "{0}" no es válida al iniciar un recurso. - - - - Restart a running resource. - Reinicie un recurso en ejecución. - - - - The name of the resource to restart. - Nombre del recurso que se va a reiniciar. - - connect to conectarse a - - Start an apphost in the background, or start a stopped resource. - Inicie un apphost en segundo plano o inicie un recurso detenido. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Nombre del recurso que se va a iniciar. Si no se especifica, inicia AppHost en segundo plano. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.fr.xlf index 922aee9eb92..506fa74c645 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.fr.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Exécuter une commande sur une ressource. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Le nom de la commande à exécuter. @@ -17,36 +17,11 @@ Nom de la ressource sur laquelle exécuter la commande. - - The '{0}' option is not valid when starting a resource. - L’option « {0} » n’est pas valide lors du démarrage d’une ressource. - - - - Restart a running resource. - Redémarrer une ressource en cours d’exécution. - - - - The name of the resource to restart. - Le nom de la ressource à redémarrer. - - connect to se connecter à - - Start an apphost in the background, or start a stopped resource. - Démarrer un AppHost en arrière-plan ou lancez une ressource arrêtée. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Le nom de la ressource à commencer. Si aucun nom n’est spécifié, démarrer AppHost en arrière-plan. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.it.xlf index 32ac962a41a..d5468f1e142 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.it.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Eseguire un comando su una risorsa. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Nome del comando da eseguire. @@ -17,36 +17,11 @@ Nome della risorsa di destinazione rispetto al quale eseguire il comando. - - The '{0}' option is not valid when starting a resource. - L'opzione '{0}' non è valida quando si avvia una risorsa. - - - - Restart a running resource. - Riavviare una risorsa in esecuzione. - - - - The name of the resource to restart. - Nome della risorsa da riavviare. - - connect to connettersi a - - Start an apphost in the background, or start a stopped resource. - Avvia un apphost in background o avvia una risorsa arrestata. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Nome della risorsa da avviare. Se non specificato, avvia AppHost in background. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ja.xlf index fc67bb7cb73..cfab15f18c0 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ja.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). リソースでコマンドを実行します。 - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). 実行するコマンドの名前。 @@ -17,36 +17,11 @@ コマンドを実行する対象のリソースの名前。 - - The '{0}' option is not valid when starting a resource. - '{0}' オプションは、リソースの開始時には無効です。 - - - - Restart a running resource. - 実行中のリソースを再起動します。 - - - - The name of the resource to restart. - 再起動するリソースの名前。 - - connect to 接続先 - - Start an apphost in the background, or start a stopped resource. - バックグラウンドで AppHost を開始するか、停止したリソースを開始します。 - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - 開始するリソースの名前。指定しない場合は、AppHost をバックグラウンドで開始します。 - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ko.xlf index 24d6d1dd722..e757a714547 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ko.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). 리소스에서 명령을 실행합니다. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). 실행할 명령의 이름입니다. @@ -17,36 +17,11 @@ 명령을 실행할 대상 리소스의 이름입니다. - - The '{0}' option is not valid when starting a resource. - 리소스를 시작할 때 '{0}' 옵션이 잘못되었습니다. - - - - Restart a running resource. - 실행 중인 리소스를 다시 시작합니다. - - - - The name of the resource to restart. - 다시 시작할 리소스의 이름입니다. - - connect to 연결 대상 - - Start an apphost in the background, or start a stopped resource. - 백그라운드에서 apphost를 시작하거나 중지된 리소스를 시작합니다. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - 시작할 리소스의 이름입니다. 지정하지 않으면 백그라운드에서 AppHost를 시작합니다. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pl.xlf index 7f680509034..85d67d18c38 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pl.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Wykonaj polecenie dla zasobu. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Nazwa polecenia do wykonania. @@ -17,36 +17,11 @@ Nazwa zasobu, na którym ma zostać wykonane polecenie. - - The '{0}' option is not valid when starting a resource. - Opcja „{0}” jest nieprawidłowa podczas uruchamiania zasobu. - - - - Restart a running resource. - Uruchom ponownie uruchomiony zasób. - - - - The name of the resource to restart. - Nazwa zasobu do ponownego uruchomienia. - - connect to połącz z - - Start an apphost in the background, or start a stopped resource. - Uruchom hosta aplikacji w tle lub uruchom zatrzymany zasób. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Nazwa zasobu do uruchomienia. Jeśli nie zostanie określona, uruchamia hosta aplikacji w tle. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pt-BR.xlf index aa3da3029e0..0191a102109 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.pt-BR.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Execute um comando em um recurso. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). O nome do comando a ser executado. @@ -17,36 +17,11 @@ O nome do recurso no qual executar o comando. - - The '{0}' option is not valid when starting a resource. - A opção '{0}' não é válida ao iniciar um recurso. - - - - Restart a running resource. - Reinicie um recurso em execução. - - - - The name of the resource to restart. - O nome do recurso a ser reiniciado. - - connect to conectar-se a - - Start an apphost in the background, or start a stopped resource. - Inicie um apphost em segundo plano ou inicie um recurso parado. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - O nome do recurso a ser iniciado. Se não for especificado, inicia o AppHost em segundo plano. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ru.xlf index 2d1038b7b89..8548bdb795a 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.ru.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Выполнить команду на ресурсе. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Имя команды, которую нужно выполнить. @@ -17,36 +17,11 @@ Имя целевого ресурса, на котором будет выполняться команда. - - The '{0}' option is not valid when starting a resource. - Параметр "{0}" недопустим при запуске ресурса. - - - - Restart a running resource. - Перезапустить уже запущенный ресурс. - - - - The name of the resource to restart. - Имя ресурса, который нужно перезапустить. - - connect to подключить к - - Start an apphost in the background, or start a stopped resource. - Запустить AppHost в фоновом режиме или запустить остановленный ресурс. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Имя ресурса, который нужно запустить. Если не указано, AppHost запускается в фоновом режиме. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.tr.xlf index 776ac08810e..aeeaac5dbd1 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.tr.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). Bir kaynak üzerinde bir komut çalıştırın. - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). Yürütülecek komutun adı. @@ -17,36 +17,11 @@ Komutu yürütecek kaynağın adı. - - The '{0}' option is not valid when starting a resource. - Kaynak başlatılırken '{0}' seçeneği geçerli değildir. - - - - Restart a running resource. - Çalışan bir kaynağı yeniden başlatın. - - - - The name of the resource to restart. - Yeniden başlatılacak kaynağın adı. - - connect to şuna bağlanın: - - Start an apphost in the background, or start a stopped resource. - Arka planda bir apphost başlatın veya durdurulmuş bir kaynağı başlatın. - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - Başlatılacak kaynağın adı. Belirtilmezse, AppHost arka planda başlatılır. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hans.xlf index ab2b23b911b..f7f4c2a99e3 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hans.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). 在资源上执行命令。 - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). 要执行的命令的名称。 @@ -17,36 +17,11 @@ 要在其上执行命令的资源的名称。 - - The '{0}' option is not valid when starting a resource. - 启动资源时,"{0}" 选项无效。 - - - - Restart a running resource. - 重启正在运行的资源。 - - - - The name of the resource to restart. - 要重启的资源的名称。 - - connect to 连接到 - - Start an apphost in the background, or start a stopped resource. - 在后台启动 apphost,或启动已停止的资源。 - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - 要启动的资源的名称。如果未指定,则在后台启动 AppHost。 - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hant.xlf index a7a2f4e530f..5bd330e582f 100644 --- a/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/ResourceCommandStrings.zh-Hant.xlf @@ -3,12 +3,12 @@ - Execute a command on a resource. + Execute a command on a resource (e.g. start, stop, restart). 在資源上執行命令。 - The name of the command to execute. + The name of the command to execute (e.g. start, stop, restart). 所要執行命令的名稱。 @@ -17,36 +17,11 @@ 要執行命令的資源名稱。 - - The '{0}' option is not valid when starting a resource. - 啟動資源時,'{0}' 選項無效。 - - - - Restart a running resource. - 重新啟動正在執行的資源。 - - - - The name of the resource to restart. - 要重新啟動的資源名稱。 - - connect to 連線至 - - Start an apphost in the background, or start a stopped resource. - 在背景啟動 apphost,或啟動已停止的資源。 - - - - The name of the resource to start. If not specified, starts the AppHost in the background. - 要啟動的資源名稱。若未指定,則會在背景啟動 AppHost。 - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.cs.xlf new file mode 100644 index 00000000000..147c6bfc7ef --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.cs.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.de.xlf new file mode 100644 index 00000000000..17f0a4aac54 --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.de.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.es.xlf new file mode 100644 index 00000000000..d6f3c308e84 --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.es.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.fr.xlf new file mode 100644 index 00000000000..4d1ecc2883a --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.fr.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.it.xlf new file mode 100644 index 00000000000..8cc171ceeef --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.it.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ja.xlf new file mode 100644 index 00000000000..248c2d08b17 --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ja.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ko.xlf new file mode 100644 index 00000000000..9a1175fd687 --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ko.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.pl.xlf new file mode 100644 index 00000000000..a919d1ee3df --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.pl.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.pt-BR.xlf new file mode 100644 index 00000000000..e48f0a6ad9a --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.pt-BR.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ru.xlf new file mode 100644 index 00000000000..4cf60b12a69 --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.ru.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.tr.xlf new file mode 100644 index 00000000000..3c08449a7aa --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.tr.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.zh-Hans.xlf new file mode 100644 index 00000000000..262dce60017 --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.zh-Hans.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StartCommandStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.zh-Hant.xlf new file mode 100644 index 00000000000..15b5f3aee34 --- /dev/null +++ b/src/Aspire.Cli/Resources/xlf/StartCommandStrings.zh-Hant.xlf @@ -0,0 +1,12 @@ + + + + + + Start an apphost in the background. + Start an apphost in the background. + + + + + diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.cs.xlf index 7b0641a7978..cb2ffbdac5b 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.cs.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Umožňuje zastavit spuštěného hostitele aplikace nebo zadaný prostředek. + Stop a running apphost. + Zastavte spuštěného hostitele aplikací Aspire. @@ -52,11 +52,6 @@ Možnosti {0} a {1} se nedají použít společně. - - The {0} option cannot be used with a resource argument. - Možnost {0} nelze použít s argumentem prostředku. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.de.xlf index 2635d9946b1..308f1bf3305 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.de.xlf @@ -1,10 +1,10 @@ - + Stop all running AppHosts. - Beenden Sie alle ausgeführten AppHosts. + Stop all running AppHosts. @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Beendet einen laufenden Apphost oder die angegebene Ressource. + Stop a running apphost. + Beenden Sie einen aktiven Aspire-AppHost. @@ -24,7 +24,7 @@ Multiple AppHosts are running. Use {0} to specify which one to stop, or use {1} to stop all of them. - Mehrere AppHosts sind aktiv. Verwenden Sie {0}, um anzugeben, welche beendet werden soll, oder {1} um sie alle zu beenden. + Multiple AppHosts are running. Use {0} to specify which one to stop, or use {1} to stop all of them. @@ -49,12 +49,7 @@ The {0} and {1} options cannot be used together. - Die Optionen {0} und {1} können nicht zusammen verwendet werden. - - - - The {0} option cannot be used with a resource argument. - Die Option „{0}“ kann nicht mit einem Ressourcenargument verwendet werden. + The {0} and {1} options cannot be used together. diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.es.xlf index 92dff68ab5b..01f8827f18d 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.es.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Detenga un apphost en ejecución o el recurso especificado. + Stop a running apphost. + Detenga un apphost en ejecución de Aspire. @@ -52,11 +52,6 @@ Las opciones {0} y {1} no se pueden usar juntas. - - The {0} option cannot be used with a resource argument. - La opción {0} no se puede usar con un argumento de recurso. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.fr.xlf index 388b3f9e5d1..a22c22fcd78 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.fr.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Arrêter un apphost en cours d’exécution ou la ressource spécifiée. + Stop a running apphost. + Arrêtez un AppHost Aspire en cours d’exécution. @@ -52,11 +52,6 @@ Les options {0} et {1} ne peuvent pas être utilisées ensemble. - - The {0} option cannot be used with a resource argument. - L’option {0} ne peut pas être utilisée avec un argument de ressource. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.it.xlf index 8c6f1dd29b6..8a0a1fca784 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.it.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Interrompere un apphost in esecuzione o la risorsa specificata. + Stop a running apphost. + Arrestare un apphost Aspire in esecuzione. @@ -52,11 +52,6 @@ Le opzioni {0} e {1} non possono essere usate insieme. - - The {0} option cannot be used with a resource argument. - L'opzione {0} non può essere usata con un argomento di risorsa. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ja.xlf index c42b08ffcd4..bad89474dc6 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ja.xlf @@ -1,10 +1,10 @@ - + Stop all running AppHosts. - 実行中のすべての AppHost を停止します。 + Stop all running AppHosts. @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - 実行中の AppHost または指定したリソースを停止します。 + Stop a running apphost. + 実行中の Aspire apphost を停止します。 @@ -24,7 +24,7 @@ Multiple AppHosts are running. Use {0} to specify which one to stop, or use {1} to stop all of them. - 複数の AppHost が実行されています。停止するものを指定するために {0} を使用するか、それらのすべてを停止するために {1} を使用します。 + Multiple AppHosts are running. Use {0} to specify which one to stop, or use {1} to stop all of them. @@ -49,12 +49,7 @@ The {0} and {1} options cannot be used together. - {0} オプションと {1} オプションは同時に使用できません。 - - - - The {0} option cannot be used with a resource argument. - {0} オプションは、リソース引数と一緒に使用できません。 + The {0} and {1} options cannot be used together. diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ko.xlf index dd51cdc2925..9f22ef1ca00 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ko.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - 실행 중인 apphost 또는 지정된 리소스를 중지합니다. + Stop a running apphost. + 실행 중인 Aspire AppHost를 중지합니다. @@ -52,11 +52,6 @@ {0} 및 {1} 옵션은 함께 사용할 수 없습니다. - - The {0} option cannot be used with a resource argument. - {0} 옵션은 리소스 인수와 함께 사용할 수 없습니다. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pl.xlf index 9172410efe7..785a990f956 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pl.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Zatrzymaj działający host aplikacji lub określony zasób. + Stop a running apphost. + Zatrzymaj uruchomiony host aplikacji Wyszukaj. @@ -52,11 +52,6 @@ Opcji {0} i {1} opcji nie można używać razem. - - The {0} option cannot be used with a resource argument. - Opcji {0} nie można używać z argumentem zasobu. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pt-BR.xlf index b9ddc56e1ad..3353519bc5d 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.pt-BR.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Parar um apphost em execução ou o recurso especificado. + Stop a running apphost. + Pare um AppHost Aspire em execução. @@ -52,11 +52,6 @@ As opções {0} e {1} não podem ser usadas juntas. - - The {0} option cannot be used with a resource argument. - A opção {0} não pode ser usada com um argumento de recurso. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ru.xlf index 77f3f9508d7..9065bdb60dd 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.ru.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Остановить запущенный хост приложений или указанный ресурс. + Stop a running apphost. + Остановить запущенный хост приложений Aspire. @@ -52,11 +52,6 @@ Параметры {0} и {1} не могут использоваться одновременно. - - The {0} option cannot be used with a resource argument. - Вариант {0} нельзя использовать с аргументом ресурса. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.tr.xlf index 38b0b0148cf..045e8405832 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.tr.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - Çalışan bir apphost'u veya belirtilen kaynağı durdurun. + Stop a running apphost. + Çalışan bir Aspire apphost'unu durdurun. @@ -52,11 +52,6 @@ {0} ve {1} seçenekleri birlikte kullanılamaz. - - The {0} option cannot be used with a resource argument. - {0} seçeneği bir kaynak bağımsız değişkeniyle kullanılamaz. - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hans.xlf index 6e23af2b9ae..4c0ae3e42d5 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - 停止正在运行的 apphost 或指定的资源。 + Stop a running apphost. + 停止一个正在运行的 Aspire AppHost。 @@ -52,11 +52,6 @@ {0} 和 {1} 选项不能一起使用。 - - The {0} option cannot be used with a resource argument. - {0} 选项不能与资源参数一起使用。 - - \ No newline at end of file diff --git a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hant.xlf index 570db6d4183..b48c04e7a71 100644 --- a/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/StopCommandStrings.zh-Hant.xlf @@ -1,10 +1,10 @@ - + Stop all running AppHosts. - 停止所有正在執行的 AppHost。 + Stop all running AppHosts. @@ -13,8 +13,8 @@ - Stop a running apphost or the specified resource. - 停止執行中的 apphost 或指定的資源。 + Stop a running apphost. + 停止正在執行的 Aspire apphost。 @@ -24,7 +24,7 @@ Multiple AppHosts are running. Use {0} to specify which one to stop, or use {1} to stop all of them. - 多個 AppHost 正在執行。請使用 {0} 指定要停止的 AppHost,或使用 {1} 停止全部。 + Multiple AppHosts are running. Use {0} to specify which one to stop, or use {1} to stop all of them. @@ -49,12 +49,7 @@ The {0} and {1} options cannot be used together. - 無法同時使用 {0} 與 {1} 選項。 - - - - The {0} option cannot be used with a resource argument. - {0} 選項無法與資源參數一起使用。 + The {0} and {1} options cannot be used together. diff --git a/src/Aspire.Cli/Scaffolding/ScaffoldingService.cs b/src/Aspire.Cli/Scaffolding/ScaffoldingService.cs index a60928588dd..14615451120 100644 --- a/src/Aspire.Cli/Scaffolding/ScaffoldingService.cs +++ b/src/Aspire.Cli/Scaffolding/ScaffoldingService.cs @@ -61,11 +61,11 @@ private async Task ScaffoldGuestLanguageAsync(ScaffoldContext context, Cancellat // Include the code generation package for scaffolding and code gen var codeGenPackage = await _languageDiscovery.GetPackageForLanguageAsync(language.LanguageId, cancellationToken); - var packages = config.GetAllPackages(sdkVersion).ToList(); + var integrations = config.GetIntegrationReferences(sdkVersion, directory.FullName).ToList(); if (codeGenPackage is not null) { var codeGenVersion = config.GetEffectiveSdkVersion(sdkVersion); - packages.Add((codeGenPackage, codeGenVersion)); + integrations.Add(IntegrationReference.FromPackage(codeGenPackage, codeGenVersion)); } var appHostServerProject = await _appHostServerProjectFactory.CreateAsync(directory.FullName, cancellationToken); @@ -73,7 +73,7 @@ private async Task ScaffoldGuestLanguageAsync(ScaffoldContext context, Cancellat var prepareResult = await _interactionService.ShowStatusAsync( "Preparing Aspire server...", - () => appHostServerProject.PrepareAsync(prepareSdkVersion, packages, cancellationToken), + () => appHostServerProject.PrepareAsync(prepareSdkVersion, integrations, cancellationToken), emoji: KnownEmojis.Gear); if (!prepareResult.Success) { diff --git a/src/Aspire.Cli/Telemetry/AspireCliTelemetry.cs b/src/Aspire.Cli/Telemetry/AspireCliTelemetry.cs index c469ea80e4d..9efb22e10df 100644 --- a/src/Aspire.Cli/Telemetry/AspireCliTelemetry.cs +++ b/src/Aspire.Cli/Telemetry/AspireCliTelemetry.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using Aspire.Hosting; +using System.Runtime.InteropServices; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -198,10 +199,14 @@ internal async Task InitializeAsync() _tagsList.Add(new(TelemetryConstants.Tags.DeviceId, deviceIdTask.Result)); // This is consistent with dashboard version data. - _tagsList.Add(new(TelemetryConstants.Tags.CliVersion, typeof(Program).Assembly.GetCustomAttribute()?.InformationalVersion ?? string.Empty)); - _tagsList.Add(new(TelemetryConstants.Tags.CliBuildId, typeof(Program).Assembly.GetCustomAttribute()?.Version ?? string.Empty)); + _tagsList.Add(new(TelemetryConstants.Tags.CliVersion, GetCliVersion())); + _tagsList.Add(new(TelemetryConstants.Tags.CliBuildId, GetCliBuildId())); _tagsList.Add(new(TelemetryConstants.Tags.DeploymentEnvironmentName, _ciEnvironmentDetector.IsCIEnvironment() ? "ci" : "local")); + + _tagsList.Add(new(TelemetryConstants.Tags.OsName, GetOsName())); + _tagsList.Add(new(TelemetryConstants.Tags.OsType, GetOsType())); + _tagsList.Add(new(TelemetryConstants.Tags.OsVersion, Environment.OSVersion.Version.ToString())); } catch (Exception ex) { @@ -241,4 +246,68 @@ private void CheckInitialization() return null; } + + /// + /// Gets the human-readable operating system name for the os.name semantic convention. + /// + internal static string GetOsName() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return "Windows"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return "Linux"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return "macOS"; + } + + return RuntimeInformation.OSDescription; + } + + /// + /// Gets the OpenTelemetry semantic convention value for the os.type attribute. + /// + internal static string GetOsType() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return "windows"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return "linux"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return "darwin"; + } + + return "unknown"; + } + + /// + /// Gets the CLI version from the assembly's informational version attribute. + /// + /// The CLI version string, or an empty string if not available. + internal static string GetCliVersion() + { + return typeof(Program).Assembly.GetCustomAttribute()?.InformationalVersion ?? string.Empty; + } + + /// + /// Gets the CLI build ID from the assembly's file version attribute. + /// + /// The CLI build ID string, or an empty string if not available. + internal static string GetCliBuildId() + { + return typeof(Program).Assembly.GetCustomAttribute()?.Version ?? string.Empty; + } } diff --git a/src/Aspire.Cli/Telemetry/TelemetryConstants.cs b/src/Aspire.Cli/Telemetry/TelemetryConstants.cs index 9fda412bff3..3bcd0888e26 100644 --- a/src/Aspire.Cli/Telemetry/TelemetryConstants.cs +++ b/src/Aspire.Cli/Telemetry/TelemetryConstants.cs @@ -87,6 +87,21 @@ internal static class Tags /// Tag indicating the result of the SDK check operation. /// public const string SdkCheckResult = "aspire.cli.sdk.check_result"; + + /// + /// Tag for the operating system name. + /// + public const string OsName = "os.name"; + + /// + /// Tag for the operating system type. + /// + public const string OsType = "os.type"; + + /// + /// Tag for the operating system version. + /// + public const string OsVersion = "os.version"; } /// diff --git a/src/Aspire.Cli/Templating/CliTemplateFactory.cs b/src/Aspire.Cli/Templating/CliTemplateFactory.cs index f916f8a39f5..fffd0575765 100644 --- a/src/Aspire.Cli/Templating/CliTemplateFactory.cs +++ b/src/Aspire.Cli/Templating/CliTemplateFactory.cs @@ -67,9 +67,24 @@ public CliTemplateFactory( _logger = logger; } + public IEnumerable GetTemplates() + { + return GetTemplateDefinitions(); + } + public Task> GetTemplatesAsync(CancellationToken cancellationToken = default) { - IEnumerable templates = + return Task.FromResult(GetTemplateDefinitions()); + } + + public Task> GetInitTemplatesAsync(CancellationToken cancellationToken = default) + { + return Task.FromResult>([]); + } + + private IEnumerable GetTemplateDefinitions() + { + return [ new CallbackTemplate( KnownTemplateId.TypeScriptStarter, @@ -95,13 +110,6 @@ public Task> GetTemplatesAsync(CancellationToken cancella languageId.Equals(KnownLanguageId.TypeScriptAlias, StringComparison.OrdinalIgnoreCase), selectableAppHostLanguages: [KnownLanguageId.CSharp, KnownLanguageId.TypeScript]) ]; - - return Task.FromResult(templates); - } - - public Task> GetInitTemplatesAsync(CancellationToken cancellationToken = default) - { - return Task.FromResult>([]); } private static string ApplyTokens(string content, string projectName, string projectNameLower, string aspireVersion, TemplatePorts ports, string hostName = "localhost") diff --git a/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs b/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs index 8f88caf1e52..5f29df6b43a 100644 --- a/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs +++ b/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs @@ -3,6 +3,7 @@ using System.CommandLine; using System.Globalization; +using System.Runtime.InteropServices; using Aspire.Cli.Certificates; using Aspire.Cli.Commands; using Aspire.Cli.Configuration; @@ -54,6 +55,18 @@ internal class DotNetTemplateFactory( Description = TemplatingStrings.EnterXUnitVersion_Description }; + public IEnumerable GetTemplates() + { + if (!IsDotNetOnPath()) + { + return []; + } + + var showAllTemplates = features.IsFeatureEnabled(KnownFeatures.ShowAllTemplates, false); + var nonInteractive = !hostEnvironment.SupportsInteractiveInput; + return GetTemplatesCore(showAllTemplates, nonInteractive); + } + public async Task> GetTemplatesAsync(CancellationToken cancellationToken = default) { if (!await IsDotNetSdkAvailableAsync(cancellationToken)) @@ -89,6 +102,37 @@ private async Task IsDotNetSdkAvailableAsync(CancellationToken cancellatio } } + private bool IsDotNetOnPath() + { + // Check the private SDK installation first. + var sdkInstallPath = Path.Combine(executionContext.SdksDirectory.FullName, "dotnet", DotNetSdkInstaller.MinimumSdkVersion); + if (Directory.Exists(sdkInstallPath)) + { + return true; + } + + // Fall back to checking for dotnet on the system PATH. + var dotnetFileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet"; + var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; + + foreach (var directory in pathVariable.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries)) + { + try + { + if (File.Exists(Path.Combine(directory, dotnetFileName))) + { + return true; + } + } + catch + { + // Skip directories that can't be accessed. + } + } + + return false; + } + private IEnumerable GetTemplatesCore(bool showAllTemplates, bool nonInteractive = false) { yield return new CallbackTemplate( diff --git a/src/Aspire.Cli/Templating/ITemplateFactory.cs b/src/Aspire.Cli/Templating/ITemplateFactory.cs index 27b3bbb76ce..d4b413674a6 100644 --- a/src/Aspire.Cli/Templating/ITemplateFactory.cs +++ b/src/Aspire.Cli/Templating/ITemplateFactory.cs @@ -5,6 +5,16 @@ namespace Aspire.Cli.Templating; internal interface ITemplateFactory { + /// + /// Gets template definitions synchronously for command registration. + /// This must not perform any I/O or async work. + /// + IEnumerable GetTemplates(); + + /// + /// Gets templates that are available for use, performing any necessary + /// runtime availability checks (e.g. SDK availability). + /// Task> GetTemplatesAsync(CancellationToken cancellationToken = default); Task> GetInitTemplatesAsync(CancellationToken cancellationToken = default); } diff --git a/src/Aspire.Cli/Templating/ITemplateProvider.cs b/src/Aspire.Cli/Templating/ITemplateProvider.cs index d22e69b9816..a739bf6449e 100644 --- a/src/Aspire.Cli/Templating/ITemplateProvider.cs +++ b/src/Aspire.Cli/Templating/ITemplateProvider.cs @@ -9,7 +9,14 @@ namespace Aspire.Cli.Templating; internal interface ITemplateProvider { /// - /// Gets templates available to the aspire new command. + /// Gets template definitions synchronously for command registration (e.g. subcommands). + /// This must not perform any I/O or async work. + /// + IEnumerable GetTemplates(); + + /// + /// Gets templates available to the aspire new command, performing any + /// necessary runtime availability checks. /// /// The templates available for project creation. Task> GetTemplatesAsync(CancellationToken cancellationToken = default); diff --git a/src/Aspire.Cli/Templating/TemplateProvider.cs b/src/Aspire.Cli/Templating/TemplateProvider.cs index 4bb10f8a140..17823acf8e6 100644 --- a/src/Aspire.Cli/Templating/TemplateProvider.cs +++ b/src/Aspire.Cli/Templating/TemplateProvider.cs @@ -20,6 +20,11 @@ public TemplateProvider(IEnumerable factories) } + public IEnumerable GetTemplates() + { + return _factories.SelectMany(static f => f.GetTemplates()); + } + public async Task> GetTemplatesAsync(CancellationToken cancellationToken = default) { var templates = await Task.WhenAll(_factories.Select(f => f.GetTemplatesAsync(cancellationToken))); diff --git a/src/Aspire.Cli/Utils/ConfigurationHelper.cs b/src/Aspire.Cli/Utils/ConfigurationHelper.cs index 743d77874c1..acfd5ee4235 100644 --- a/src/Aspire.Cli/Utils/ConfigurationHelper.cs +++ b/src/Aspire.Cli/Utils/ConfigurationHelper.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Configuration; namespace Aspire.Cli.Utils; @@ -30,13 +32,13 @@ internal static void RegisterSettingsFiles(IConfigurationBuilder configuration, // Add global settings first (if it exists) - lower precedence if (File.Exists(globalSettingsFile.FullName)) { - configuration.AddJsonFile(globalSettingsFile.FullName, optional: true); + AddSettingsFile(configuration, globalSettingsFile.FullName); } // Then add local settings (if found) - this will override global settings if (localSettingsFile is not null) { - configuration.AddJsonFile(localSettingsFile.FullName, optional: true); + AddSettingsFile(configuration, localSettingsFile.FullName); } } @@ -44,4 +46,143 @@ internal static string BuildPathToSettingsJsonFile(string workingDirectory) { return Path.Combine(workingDirectory, ".aspire", "settings.json"); } + + /// + /// Serializes a JsonObject and writes it to a settings file, creating the directory if needed. + /// + internal static async Task WriteSettingsFileAsync(string filePath, JsonObject settings, CancellationToken cancellationToken = default) + { + var jsonContent = JsonSerializer.Serialize(settings, JsonSourceGenerationContext.Default.JsonObject); + + EnsureDirectoryExists(filePath); + await File.WriteAllTextAsync(filePath, jsonContent, cancellationToken); + } + + /// + /// Serializes a JsonObject and writes it to a settings file, creating the directory if needed. + /// + internal static void WriteSettingsFile(string filePath, JsonObject settings) + { + var jsonContent = JsonSerializer.Serialize(settings, JsonSourceGenerationContext.Default.JsonObject); + + EnsureDirectoryExists(filePath); + File.WriteAllText(filePath, jsonContent); + } + + private static void EnsureDirectoryExists(string filePath) + { + var directory = Path.GetDirectoryName(filePath); + if (directory is not null && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + } + + private static void AddSettingsFile(IConfigurationBuilder configuration, string filePath) + { + // Proactively normalize the settings file to prevent duplicate key errors. + // This handles files corrupted by mixing colon and dot notation + // (e.g., both "features:key" flat entry and "features" nested object). + TryNormalizeSettingsFile(filePath); + + configuration.AddJsonFile(filePath, optional: true); + } + + /// + /// Normalizes a settings file by converting flat colon-separated keys to nested JSON objects. + /// + internal static bool TryNormalizeSettingsFile(string filePath) + { + try + { + var content = File.ReadAllText(filePath); + + if (string.IsNullOrWhiteSpace(content)) + { + return false; + } + + var settings = JsonNode.Parse(content)?.AsObject(); + + if (settings is null) + { + return false; + } + + // Find all colon-separated keys at root level + var colonKeys = new List<(string key, string? value)>(); + + foreach (var kvp in settings) + { + if (kvp.Key.Contains(':')) + { + colonKeys.Add((kvp.Key, kvp.Value?.ToString())); + } + } + + if (colonKeys.Count == 0) + { + return false; + } + + // Remove colon keys and re-add them as nested structure + foreach (var (key, value) in colonKeys) + { + settings.Remove(key); + + // Convert "a:b:c" to nested {"a": {"b": {"c": value}}} + var parts = key.Split(':'); + var currentObject = settings; + var pathConflict = false; + + // Walk all but the last segment, creating objects as needed. + for (int i = 0; i < parts.Length - 1; i++) + { + var part = parts[i]; + + if (!currentObject.ContainsKey(part) || currentObject[part] is null) + { + currentObject[part] = new JsonObject(); + } + else if (currentObject[part] is JsonObject) + { + currentObject = currentObject[part]!.AsObject(); + continue; + } + else + { + // Existing non-object value conflicts with the desired nested structure. + // Prefer the existing nested value and drop the flat key. + pathConflict = true; + break; + } + + currentObject = currentObject[part]!.AsObject(); + } + + if (pathConflict) + { + continue; + } + + var finalKey = parts[parts.Length - 1]; + + // If the final key already exists, keep its value and drop the flat key. + if (currentObject.ContainsKey(finalKey) && currentObject[finalKey] is not null) + { + continue; + } + + currentObject[finalKey] = value; + } + + WriteSettingsFile(filePath, settings); + + return true; + } + catch + { + return false; + } + } } diff --git a/src/Aspire.Dashboard/Mcp/AspireResourceMcpTools.cs b/src/Aspire.Dashboard/Mcp/AspireResourceMcpTools.cs index 6b949875440..c19fc7f3090 100644 --- a/src/Aspire.Dashboard/Mcp/AspireResourceMcpTools.cs +++ b/src/Aspire.Dashboard/Mcp/AspireResourceMcpTools.cs @@ -71,7 +71,7 @@ private static List GetFilteredResources(List ListConsoleLogsAsync( [Description("The resource name.")] string resourceName, @@ -167,9 +167,9 @@ public async Task ExecuteResourceCommand([Description("The resource name")] stri if (command.State == CommandViewModelState.Disabled) { - if (command.Name == "resource-restart" && resource.Commands.Any(c => c.Name == "resource-start" && c.State == CommandViewModelState.Enabled)) + if (command.Name == CommandViewModel.RestartCommand && resource.Commands.Any(c => c.Name == CommandViewModel.StartCommand && c.State == CommandViewModelState.Enabled)) { - throw new McpProtocolException($"Resource '{resourceName}' is stopped. Use the 'resource-start' command instead of 'resource-restart'.", McpErrorCode.InvalidParams); + throw new McpProtocolException($"Resource '{resourceName}' is stopped. Use the '{CommandViewModel.StartCommand}' command instead of '{CommandViewModel.RestartCommand}'.", McpErrorCode.InvalidParams); } throw new McpProtocolException($"Command '{commandName}' is currently disabled for resource '{resourceName}'.", McpErrorCode.InvalidParams); diff --git a/src/Aspire.Dashboard/Mcp/McpExtensions.cs b/src/Aspire.Dashboard/Mcp/McpExtensions.cs index 6c2dd726ea7..a307bf91b70 100644 --- a/src/Aspire.Dashboard/Mcp/McpExtensions.cs +++ b/src/Aspire.Dashboard/Mcp/McpExtensions.cs @@ -48,19 +48,20 @@ public static IMcpServerBuilder AddAspireMcpTools(this IServiceCollection servic } builder - .AddListToolsFilter((next) => async (RequestContext request, CancellationToken cancellationToken) => - { - // Calls here are via the tools/list endpoint. See https://modelcontextprotocol.info/docs/concepts/tools/ - // There is no tool name so we hardcode name to list_tools here so we can reuse the same event. - // - // We want to track when users list tools as it's an indicator of whether Aspire MCP is configured (client tools refresh tools via it). - // It's called even if no Aspire tools end up being used. - return await RecordCallToolNameAsync(next, request, "list_tools", cancellationToken).ConfigureAwait(false); - }) - .AddCallToolFilter((next) => async (RequestContext request, CancellationToken cancellationToken) => - { - return await RecordCallToolNameAsync(next, request, request.Params?.Name, cancellationToken).ConfigureAwait(false); - }); + .WithRequestFilters(filters => filters + .AddListToolsFilter((next) => async (RequestContext request, CancellationToken cancellationToken) => + { + // Calls here are via the tools/list endpoint. See https://modelcontextprotocol.info/docs/concepts/tools/ + // There is no tool name so we hardcode name to list_tools here so we can reuse the same event. + // + // We want to track when users list tools as it's an indicator of whether Aspire MCP is configured (client tools refresh tools via it). + // It's called even if no Aspire tools end up being used. + return await RecordCallToolNameAsync(next, request, "list_tools", cancellationToken).ConfigureAwait(false); + }) + .AddCallToolFilter((next) => async (RequestContext request, CancellationToken cancellationToken) => + { + return await RecordCallToolNameAsync(next, request, request.Params?.Name, cancellationToken).ConfigureAwait(false); + })); return builder; } diff --git a/src/Aspire.Dashboard/Model/Assistant/AssistantChatDataContext.cs b/src/Aspire.Dashboard/Model/Assistant/AssistantChatDataContext.cs index a12198b516e..8cebb29ba0f 100644 --- a/src/Aspire.Dashboard/Model/Assistant/AssistantChatDataContext.cs +++ b/src/Aspire.Dashboard/Model/Assistant/AssistantChatDataContext.cs @@ -229,7 +229,7 @@ public async Task GetTraceStructuredLogsAsync( return response; } - [Description("Get console logs for a resource. The console logs includes standard output from resources and resource commands. Known resource commands are 'resource-start', 'resource-stop' and 'resource-restart' which are used to start and stop resources. Don't print the full console logs in the response to the user. Console logs should be examined when determining why a resource isn't running.")] + [Description("Get console logs for a resource. The console logs includes standard output from resources and resource commands. Known resource commands are 'start', 'stop' and 'restart' which are used to start and stop resources. Don't print the full console logs in the response to the user. Console logs should be examined when determining why a resource isn't running.")] public async Task GetConsoleLogsAsync( [Description("The resource name.")] string resourceName, diff --git a/src/Aspire.Dashboard/Model/ResourceViewModel.cs b/src/Aspire.Dashboard/Model/ResourceViewModel.cs index c9c371ae6eb..035910b7873 100644 --- a/src/Aspire.Dashboard/Model/ResourceViewModel.cs +++ b/src/Aspire.Dashboard/Model/ResourceViewModel.cs @@ -225,9 +225,9 @@ public sealed class CommandViewModel { // Known resource command constants. // Keep in sync with KnownResourceCommands in Aspire.Hosting. - public const string StartCommand = "resource-start"; - public const string StopCommand = "resource-stop"; - public const string RestartCommand = "resource-restart"; + public const string StartCommand = "start"; + public const string StopCommand = "stop"; + public const string RestartCommand = "restart"; private static readonly string[] s_knownResourceCommands = [StartCommand, StopCommand, RestartCommand]; public string Name { get; } diff --git a/src/Aspire.Hosting.Azure.AppConfiguration/AzureAppConfigurationExtensions.cs b/src/Aspire.Hosting.Azure.AppConfiguration/AzureAppConfigurationExtensions.cs index 60649e25038..b6ab399afeb 100644 --- a/src/Aspire.Hosting.Azure.AppConfiguration/AzureAppConfigurationExtensions.cs +++ b/src/Aspire.Hosting.Azure.AppConfiguration/AzureAppConfigurationExtensions.cs @@ -29,6 +29,7 @@ public static class AzureAppConfigurationExtensions /// /// These can be replaced by calling . /// + [AspireExport("addAzureAppConfiguration", Description = "Adds an Azure App Configuration resource")] public static IResourceBuilder AddAzureAppConfiguration(this IDistributedApplicationBuilder builder, [ResourceName] string name) { ArgumentNullException.ThrowIfNull(builder); @@ -92,6 +93,7 @@ public static IResourceBuilder AddAzureAppConfigu /// The Azure App Configuration resource builder. /// Callback that exposes underlying container used for emulation to allow for customization. /// A reference to the . + [AspireExport("runAsEmulator", Description = "Configures Azure App Configuration to run with the local emulator")] public static IResourceBuilder RunAsEmulator(this IResourceBuilder builder, Action>? configureEmulator = null) { if (builder.ApplicationBuilder.ExecutionContext.IsPublishMode) @@ -125,6 +127,7 @@ public static IResourceBuilder RunAsEmulator(this /// The builder for the . /// Relative path to the AppHost where emulator storage is persisted between runs. Defaults to the path '.aace' /// A builder for the . + [AspireExport("withDataBindMount", Description = "Adds a data bind mount for the App Configuration emulator")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string? path = null) { ArgumentNullException.ThrowIfNull(builder); @@ -138,6 +141,7 @@ public static IResourceBuilder WithDataBi /// The builder for the . /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// A builder for the . + [AspireExport("withDataVolume", Description = "Adds a data volume for the App Configuration emulator")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null) { ArgumentNullException.ThrowIfNull(builder); @@ -151,6 +155,7 @@ public static IResourceBuilder WithDataVo /// Builder for the Azure App Configuration emulator container /// The port to bind on the host. If is used, a random port will be assigned. /// A reference to the . + [AspireExport("withHostPort", Description = "Sets the host port for the App Configuration emulator")] public static IResourceBuilder WithHostPort(this IResourceBuilder builder, int? port) { ArgumentNullException.ThrowIfNull(builder); @@ -170,6 +175,7 @@ public static IResourceBuilder WithHostPo /// The built-in App Configuration roles to be assigned. /// The updated with the applied role assignments. /// + /// This overload is not available in polyglot app hosts. Use instead. /// /// Assigns the AppConfigurationDataReader role to the 'Projects.Api' project. /// @@ -183,6 +189,7 @@ public static IResourceBuilder WithHostPo /// /// /// + [AspireExportIgnore(Reason = "AppConfigurationBuiltInRole is an Azure.Provisioning type not compatible with ATS. Use the AzureAppConfigurationRole-based overload instead.")] public static IResourceBuilder WithRoleAssignments( this IResourceBuilder builder, IResourceBuilder target, @@ -192,6 +199,41 @@ public static IResourceBuilder WithRoleAssignments( return builder.WithRoleAssignments(target, AppConfigurationBuiltInRole.GetBuiltInRoleName, roles); } + /// + /// Assigns the specified roles to the given resource, granting it the necessary permissions + /// on the target Azure App Configuration resource. This replaces the default role assignments for the resource. + /// + /// The resource to which the specified roles will be assigned. + /// The target Azure App Configuration resource. + /// The App Configuration roles to be assigned. + /// The updated with the applied role assignments. + /// Thrown when a role value is not a valid value. + [AspireExport("withRoleAssignments", Description = "Assigns App Configuration roles to a resource")] + internal static IResourceBuilder WithRoleAssignments( + this IResourceBuilder builder, + IResourceBuilder target, + params AzureAppConfigurationRole[] roles) + where T : IResource + { + if (roles is null || roles.Length == 0) + { + return builder.WithRoleAssignments(target, Array.Empty()); + } + + var builtInRoles = new AppConfigurationBuiltInRole[roles.Length]; + for (var i = 0; i < roles.Length; i++) + { + builtInRoles[i] = roles[i] switch + { + AzureAppConfigurationRole.AppConfigurationDataOwner => AppConfigurationBuiltInRole.AppConfigurationDataOwner, + AzureAppConfigurationRole.AppConfigurationDataReader => AppConfigurationBuiltInRole.AppConfigurationDataReader, + _ => throw new ArgumentException($"Role '{roles[i]}' at index {i} is not a valid {nameof(AzureAppConfigurationRole)} value.", nameof(roles)) + }; + } + + return builder.WithRoleAssignments(target, builtInRoles); + } + /// /// Configures anonymous authentication for the Azure App Configuration emulator resource. /// diff --git a/src/Aspire.Hosting.Azure.AppConfiguration/AzureAppConfigurationRole.cs b/src/Aspire.Hosting.Azure.AppConfiguration/AzureAppConfigurationRole.cs new file mode 100644 index 00000000000..1339c5aa6f6 --- /dev/null +++ b/src/Aspire.Hosting.Azure.AppConfiguration/AzureAppConfigurationRole.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting; + +/// +/// Represents Azure App Configuration roles that are compatible with the Aspire Type System (ATS). +/// +internal enum AzureAppConfigurationRole +{ + AppConfigurationDataOwner, + AppConfigurationDataReader, +} diff --git a/src/Aspire.Hosting.Azure.ContainerRegistry/AzureContainerRegistryExtensions.cs b/src/Aspire.Hosting.Azure.ContainerRegistry/AzureContainerRegistryExtensions.cs index 43a0b3d492a..8b4c40c6041 100644 --- a/src/Aspire.Hosting.Azure.ContainerRegistry/AzureContainerRegistryExtensions.cs +++ b/src/Aspire.Hosting.Azure.ContainerRegistry/AzureContainerRegistryExtensions.cs @@ -27,6 +27,7 @@ public static class AzureContainerRegistryExtensions /// A reference to the builder. /// Thrown when is null. /// Thrown when is null or empty. + [AspireExport("addAzureContainerRegistry", Description = "Adds an Azure Container Registry resource to the distributed application model.")] public static IResourceBuilder AddAzureContainerRegistry(this IDistributedApplicationBuilder builder, [ResourceName] string name) { ArgumentNullException.ThrowIfNull(builder); @@ -160,6 +161,7 @@ public static IResourceBuilder GetAzureContainer /// .WithPurgeTask("0 1 * * *", ago: TimeSpan.FromDays(7), keep: 5); /// /// + [AspireExport("withPurgeTask", Description = "Configures a purge task for the Azure Container Registry resource.")] public static IResourceBuilder WithPurgeTask( this IResourceBuilder builder, string schedule, diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs index 0d7e9f60b85..7e1eafa2675 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs @@ -18,6 +18,7 @@ namespace Aspire.Hosting.Azure; /// Use to configure specific properties. /// [DebuggerDisplay("Type = {GetType().Name,nq}, Name = {Name}, Hub = {HubName}")] +[AspireExport(ExposeProperties = true)] public class AzureEventHubResource(string name, string hubName, AzureEventHubsResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { @@ -35,11 +36,15 @@ public class AzureEventHubResource(string name, string hubName, AzureEventHubsRe /// /// Gets the parent Azure Event Hubs resource. /// + /// This property is not available in polyglot app hosts. + [AspireExportIgnore] public AzureEventHubsResource Parent { get; } = parent ?? throw new ArgumentNullException(nameof(parent)); /// /// Gets the connection string expression for the Azure Event Hub. /// + /// This property is not available in polyglot app hosts. + [AspireExportIgnore] public ReferenceExpression ConnectionStringExpression => Parent.GetConnectionString(HubName); /// diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs index a8534721741..f93eb6a242e 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs @@ -37,6 +37,7 @@ public static class AzureEventHubsExtensions /// /// These can be replaced by calling . /// + [AspireExport("addAzureEventHubs", Description = "Adds an Azure Event Hubs namespace resource")] public static IResourceBuilder AddAzureEventHubs( this IDistributedApplicationBuilder builder, [ResourceName] string name) { @@ -151,6 +152,7 @@ public static IResourceBuilder AddEventHub(this IResourc /// The name of the Event Hub resource. /// The name of the Event Hub. If not provided, this defaults to the same value as . /// A reference to the . + [AspireExport("addHub", Description = "Adds an Azure Event Hub resource")] public static IResourceBuilder AddHub(this IResourceBuilder builder, [ResourceName] string name, string? hubName = null) { ArgumentNullException.ThrowIfNull(builder); @@ -171,6 +173,7 @@ public static IResourceBuilder AddHub(this IResourceBuild /// The Azure Event Hub resource builder. /// A method that can be used for customizing the . /// A reference to the . + [AspireExport("withProperties", Description = "Configures properties of an Azure Event Hub")] public static IResourceBuilder WithProperties(this IResourceBuilder builder, Action configure) { ArgumentNullException.ThrowIfNull(builder); @@ -188,6 +191,7 @@ public static IResourceBuilder WithProperties(this IResou /// The name of the Event Hub Consumer Group resource. /// The name of the Consumer Group. If not provided, this defaults to the same value as . /// A reference to the . + [AspireExport("addConsumerGroup", Description = "Adds an Azure Event Hub consumer group resource")] public static IResourceBuilder AddConsumerGroup( this IResourceBuilder builder, [ResourceName] string name, @@ -233,6 +237,7 @@ public static IResourceBuilder AddConsumerGr /// builder.Build().Run(); /// /// + [AspireExport("runAsEmulator", Description = "Configures the Azure Event Hubs resource to run with the local emulator")] public static IResourceBuilder RunAsEmulator(this IResourceBuilder builder, Action>? configureContainer = null) { ArgumentNullException.ThrowIfNull(builder); @@ -399,6 +404,7 @@ public static IResourceBuilder WithGatewayPort(t /// Builder for the Azure Event Hubs emulator container /// The port to bind on the host. If is used, a random port will be assigned. /// Azure Event Hubs emulator resource builder. + [AspireExport("withHostPort", Description = "Sets the host port for the Event Hubs emulator endpoint")] public static IResourceBuilder WithHostPort(this IResourceBuilder builder, int? port) { ArgumentNullException.ThrowIfNull(builder); @@ -415,6 +421,7 @@ public static IResourceBuilder WithHostPort(this /// The builder for the . /// Path to the file on the AppHost where the emulator configuration is located. /// A reference to the . + [AspireExport("withConfigurationFile", Description = "Sets the emulator configuration file path")] public static IResourceBuilder WithConfigurationFile(this IResourceBuilder builder, string path) { ArgumentNullException.ThrowIfNull(builder); @@ -429,6 +436,8 @@ public static IResourceBuilder WithConfiguration /// The builder for the . /// A callback to update the JSON object representation of the configuration. /// A reference to the . + /// This method is not available in polyglot app hosts. Use instead. + [AspireExportIgnore(Reason = "Action callbacks are not ATS-compatible.")] public static IResourceBuilder WithConfiguration(this IResourceBuilder builder, Action configJson) { ArgumentNullException.ThrowIfNull(builder); @@ -496,6 +505,12 @@ private static string CreateEmulatorConfigJson(AzureEventHubsResource emulatorRe /// .WithReference(eventHubs); /// /// + /// + /// This overload is not available in polyglot app hosts. Use + /// + /// instead. + /// + [AspireExportIgnore(Reason = "EventHubsBuiltInRole is an Azure.Provisioning type not compatible with ATS. Use the AzureEventHubsRole-based overload instead.")] public static IResourceBuilder WithRoleAssignments( this IResourceBuilder builder, IResourceBuilder target, @@ -504,4 +519,40 @@ public static IResourceBuilder WithRoleAssignments( { return builder.WithRoleAssignments(target, EventHubsBuiltInRole.GetBuiltInRoleName, roles); } + + /// + /// Assigns the specified roles to the given resource, granting it the necessary permissions + /// on the target Azure Event Hubs Namespace resource. This replaces the default role assignments for the resource. + /// + /// The resource to which the specified roles will be assigned. + /// The target Azure Event Hubs Namespace resource. + /// The Event Hubs roles to be assigned. + /// The updated with the applied role assignments. + /// Thrown when a role value is not a valid value. + [AspireExport("withRoleAssignments", Description = "Assigns Event Hubs roles to a resource")] + internal static IResourceBuilder WithRoleAssignments( + this IResourceBuilder builder, + IResourceBuilder target, + params AzureEventHubsRole[] roles) + where T : IResource + { + if (roles is null || roles.Length == 0) + { + return builder.WithRoleAssignments(target, Array.Empty()); + } + + var builtInRoles = new EventHubsBuiltInRole[roles.Length]; + for (var i = 0; i < roles.Length; i++) + { + builtInRoles[i] = roles[i] switch + { + AzureEventHubsRole.AzureEventHubsDataOwner => EventHubsBuiltInRole.AzureEventHubsDataOwner, + AzureEventHubsRole.AzureEventHubsDataReceiver => EventHubsBuiltInRole.AzureEventHubsDataReceiver, + AzureEventHubsRole.AzureEventHubsDataSender => EventHubsBuiltInRole.AzureEventHubsDataSender, + _ => throw new ArgumentException($"Invalid Event Hubs role: {roles[i]}.", nameof(roles)) + }; + } + + return builder.WithRoleAssignments(target, builtInRoles); + } } diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsRole.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsRole.cs new file mode 100644 index 00000000000..e5c7296ea52 --- /dev/null +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsRole.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting; + +/// +/// Represents ATS-compatible Azure Event Hubs roles. +/// +internal enum AzureEventHubsRole +{ + AzureEventHubsDataOwner, + AzureEventHubsDataReceiver, + AzureEventHubsDataSender, +} diff --git a/src/Aspire.Hosting.Azure.Redis/AzureManagedRedisExtensions.cs b/src/Aspire.Hosting.Azure.Redis/AzureManagedRedisExtensions.cs index b540998e385..996ac06173a 100644 --- a/src/Aspire.Hosting.Azure.Redis/AzureManagedRedisExtensions.cs +++ b/src/Aspire.Hosting.Azure.Redis/AzureManagedRedisExtensions.cs @@ -43,6 +43,7 @@ public static class AzureManagedRedisExtensions /// /// /// + [AspireExport("addAzureManagedRedis", Description = "Adds an Azure Managed Redis resource")] public static IResourceBuilder AddAzureManagedRedis( this IDistributedApplicationBuilder builder, [ResourceName] string name) @@ -80,6 +81,7 @@ public static IResourceBuilder AddAzureManagedRedis( /// /// /// + [AspireExport("runAsContainer", Description = "Configures Azure Managed Redis to run in a local container")] public static IResourceBuilder RunAsContainer( this IResourceBuilder builder, Action>? configureContainer = null) @@ -124,6 +126,7 @@ public static IResourceBuilder RunAsContainer( /// /// /// + [AspireExport("withAccessKeyAuthentication", Description = "Configures Azure Managed Redis to use access key authentication")] public static IResourceBuilder WithAccessKeyAuthentication(this IResourceBuilder builder) { ArgumentNullException.ThrowIfNull(builder); @@ -154,6 +157,7 @@ public static IResourceBuilder WithAccessKeyAuthentic /// The Azure Managed Redis resource builder. /// The Azure Key Vault resource builder where the connection string used to connect to this AzureManagedRedisResource will be stored. /// A reference to the builder. + [AspireExport("withAccessKeyAuthenticationWithKeyVault", Description = "Configures Azure Managed Redis to use access key authentication with a specific Key Vault")] public static IResourceBuilder WithAccessKeyAuthentication(this IResourceBuilder builder, IResourceBuilder keyVaultBuilder) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.Azure.Search/AzureSearchExtensions.cs b/src/Aspire.Hosting.Azure.Search/AzureSearchExtensions.cs index 86a688b3838..c458e1f7384 100644 --- a/src/Aspire.Hosting.Azure.Search/AzureSearchExtensions.cs +++ b/src/Aspire.Hosting.Azure.Search/AzureSearchExtensions.cs @@ -30,6 +30,7 @@ public static class AzureSearchExtensions /// /// These can be replaced by calling . /// + [AspireExport("addAzureSearch", Description = "Adds an Azure AI Search service resource")] public static IResourceBuilder AddAzureSearch(this IDistributedApplicationBuilder builder, [ResourceName] string name) { ArgumentNullException.ThrowIfNull(builder); @@ -121,6 +122,12 @@ void ConfigureSearch(AzureResourceInfrastructure infrastructure) /// /// /// + /// + /// This overload is not available in polyglot app hosts. Use + /// + /// instead. + /// + [AspireExportIgnore(Reason = "SearchBuiltInRole is an Azure.Provisioning type not compatible with ATS. Use the AzureSearchRole-based overload instead.")] public static IResourceBuilder WithRoleAssignments( this IResourceBuilder builder, IResourceBuilder target, @@ -129,4 +136,40 @@ public static IResourceBuilder WithRoleAssignments( { return builder.WithRoleAssignments(target, SearchBuiltInRole.GetBuiltInRoleName, roles); } + + /// + /// Assigns the specified roles to the given resource, granting it the necessary permissions + /// on the target Azure AI Search service resource. This replaces the default role assignments for the resource. + /// + /// The resource to which the specified roles will be assigned. + /// The target Azure AI Search service resource. + /// The Azure AI Search roles to be assigned. + /// The updated with the applied role assignments. + /// Thrown when a role value is not a valid value. + [AspireExport("withRoleAssignments", Description = "Assigns Azure AI Search roles to a resource")] + internal static IResourceBuilder WithRoleAssignments( + this IResourceBuilder builder, + IResourceBuilder target, + params AzureSearchRole[] roles) + where T : IResource + { + if (roles is null || roles.Length == 0) + { + return builder.WithRoleAssignments(target, Array.Empty()); + } + + var builtInRoles = new SearchBuiltInRole[roles.Length]; + for (var i = 0; i < roles.Length; i++) + { + builtInRoles[i] = roles[i] switch + { + AzureSearchRole.SearchIndexDataContributor => SearchBuiltInRole.SearchIndexDataContributor, + AzureSearchRole.SearchIndexDataReader => SearchBuiltInRole.SearchIndexDataReader, + AzureSearchRole.SearchServiceContributor => SearchBuiltInRole.SearchServiceContributor, + _ => throw new ArgumentException($"Invalid Azure AI Search role: {roles[i]}.", nameof(roles)) + }; + } + + return builder.WithRoleAssignments(target, builtInRoles); + } } diff --git a/src/Aspire.Hosting.Azure.Search/AzureSearchRole.cs b/src/Aspire.Hosting.Azure.Search/AzureSearchRole.cs new file mode 100644 index 00000000000..33b2f59390c --- /dev/null +++ b/src/Aspire.Hosting.Azure.Search/AzureSearchRole.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting; + +/// +/// Represents ATS-compatible Azure AI Search roles. +/// +internal enum AzureSearchRole +{ + SearchIndexDataContributor, + SearchIndexDataReader, + SearchServiceContributor, +} diff --git a/src/Aspire.Hosting.Azure.SignalR/AzureSignalRExtensions.cs b/src/Aspire.Hosting.Azure.SignalR/AzureSignalRExtensions.cs index ebcc31ef56c..8a723d342ba 100644 --- a/src/Aspire.Hosting.Azure.SignalR/AzureSignalRExtensions.cs +++ b/src/Aspire.Hosting.Azure.SignalR/AzureSignalRExtensions.cs @@ -31,6 +31,7 @@ public static class AzureSignalRExtensions /// /// These can be replaced by calling . /// + [AspireExportIgnore(Reason = "Use the dedicated polyglot overload instead.")] public static IResourceBuilder AddAzureSignalR(this IDistributedApplicationBuilder builder, [ResourceName] string name) => AddAzureSignalR(builder, name, AzureSignalRServiceMode.Default); @@ -52,6 +53,7 @@ public static IResourceBuilder AddAzureSignalR(this IDistr /// /// These can be replaced by calling . /// + [AspireExportIgnore(Reason = "Use the dedicated polyglot overload instead.")] public static IResourceBuilder AddAzureSignalR(this IDistributedApplicationBuilder builder, [ResourceName] string name, AzureSignalRServiceMode serviceMode) { ArgumentNullException.ThrowIfNull(builder); @@ -125,6 +127,10 @@ public static IResourceBuilder AddAzureSignalR(this IDistr .WithDefaultRoleAssignments(SignalRBuiltInRole.GetBuiltInRoleName, defaultRoles.ToArray()); } + [AspireExport("addAzureSignalR", Description = "Adds an Azure SignalR resource to the application model.")] + internal static IResourceBuilder AddAzureSignalRForPolyglot(this IDistributedApplicationBuilder builder, [ResourceName] string name) + => AddAzureSignalR(builder, name); + /// /// Configures an Azure SignalR resource to be emulated. This resource requires an to be added to the application model. Please note that the resource will be emulated in Serverless mode. /// @@ -134,6 +140,7 @@ public static IResourceBuilder AddAzureSignalR(this IDistr /// The Azure SignalR resource builder. /// Callback that exposes underlying container used for emulation to allow for customization. /// A reference to the . + [AspireExport("runAsEmulator", Description = "Configures an Azure SignalR resource to be emulated. This resource requires an to be added to the application model. Please note that the resource will be emulated in Serverless mode.")] public static IResourceBuilder RunAsEmulator(this IResourceBuilder builder, Action>? configureContainer = null) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs b/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs index 0761d3d3952..154492320b4 100644 --- a/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs +++ b/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs @@ -31,6 +31,7 @@ public static class AzureWebPubSubExtensions /// /// These can be replaced by calling . /// + [AspireExport("addAzureWebPubSub", Description = "Adds an Azure Web PubSub resource to the distributed application model.")] public static IResourceBuilder AddAzureWebPubSub(this IDistributedApplicationBuilder builder, [ResourceName] string name) { ArgumentNullException.ThrowIfNull(builder); @@ -168,6 +169,7 @@ public static IResourceBuilder AddHub(this IResourceB /// The name of the Azure WebPubSub Hub resource. /// The name of the Azure WebPubSub Hub. If not provided, this defaults to the same value as . /// A reference to the . + [AspireExport("addHub", Description = "Adds a hub to the Azure Web PubSub resource.")] public static IResourceBuilder AddHub(this IResourceBuilder builder, [ResourceName] string name, string? hubName = null) { ArgumentNullException.ThrowIfNull(builder); @@ -196,6 +198,7 @@ public static IResourceBuilder AddHub(this IResourceB /// The auth settings configured for the event handler. /// #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + [AspireExport("addEventHandler1", MethodName = "addEventHandler", Description = "Adds an event handler to an Azure Web PubSub hub.")] public static IResourceBuilder AddEventHandler( this IResourceBuilder builder, #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -221,6 +224,7 @@ public static IResourceBuilder AddEventHandler( /// The auth settings configured for the event handler. /// #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + [AspireExport("addEventHandler2", MethodName = "addEventHandler", Description = "Adds an event handler to an Azure Web PubSub hub.")] public static IResourceBuilder AddEventHandler( this IResourceBuilder builder, #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -266,6 +270,9 @@ private static WebPubSubEventHandler GetWebPubSubEventHandler(BicepValue /// The built-in Web PubSub roles to be assigned. /// The updated with the applied role assignments. /// + /// This overload is not available in polyglot app hosts. Use + /// + /// instead. /// /// Assigns the WebPubSubServiceReader role to the 'Projects.Api' project. /// @@ -279,6 +286,7 @@ private static WebPubSubEventHandler GetWebPubSubEventHandler(BicepValue /// /// /// + [AspireExportIgnore(Reason = "WebPubSubBuiltInRole is an Azure.Provisioning type not compatible with ATS. Use the AzureWebPubSubRole-based overload instead.")] public static IResourceBuilder WithRoleAssignments( this IResourceBuilder builder, IResourceBuilder target, @@ -287,4 +295,40 @@ public static IResourceBuilder WithRoleAssignments( { return builder.WithRoleAssignments(target, WebPubSubBuiltInRole.GetBuiltInRoleName, roles); } + + /// + /// Assigns the specified roles to the given resource, granting it the necessary permissions + /// on the target Azure Web PubSub resource. This replaces the default role assignments for the resource. + /// + /// The resource to which the specified roles will be assigned. + /// The target Azure Web PubSub resource. + /// The Web PubSub roles to be assigned. + /// The updated with the applied role assignments. + /// Thrown when a role value is not a valid value. + [AspireExport("withRoleAssignments", Description = "Assigns Azure Web PubSub roles to a resource")] + internal static IResourceBuilder WithRoleAssignments( + this IResourceBuilder builder, + IResourceBuilder target, + params AzureWebPubSubRole[] roles) + where T : IResource + { + if (roles is null || roles.Length == 0) + { + return builder.WithRoleAssignments(target, Array.Empty()); + } + + var builtInRoles = new WebPubSubBuiltInRole[roles.Length]; + for (var i = 0; i < roles.Length; i++) + { + builtInRoles[i] = roles[i] switch + { + AzureWebPubSubRole.WebPubSubContributor => WebPubSubBuiltInRole.WebPubSubContributor, + AzureWebPubSubRole.WebPubSubServiceOwner => WebPubSubBuiltInRole.WebPubSubServiceOwner, + AzureWebPubSubRole.WebPubSubServiceReader => WebPubSubBuiltInRole.WebPubSubServiceReader, + _ => throw new ArgumentException($"'{roles[i]}' is not a valid {nameof(AzureWebPubSubRole)} value.", nameof(roles)) + }; + } + + return builder.WithRoleAssignments(target, builtInRoles); + } } diff --git a/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubRole.cs b/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubRole.cs new file mode 100644 index 00000000000..18b11da604d --- /dev/null +++ b/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubRole.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting; + +/// +/// Represents ATS-compatible Azure Web PubSub roles. +/// +internal enum AzureWebPubSubRole +{ + WebPubSubContributor, + WebPubSubServiceOwner, + WebPubSubServiceReader, +} diff --git a/src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.ts b/src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.ts index 6b9a4acae98..7bddd74beff 100644 --- a/src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.ts +++ b/src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/transport.ts @@ -263,10 +263,27 @@ export function registerCallback( if (argArray.length > 0) { // Spread positional arguments to callback - return await callback(...argArray); + const result = await callback(...argArray); + // DTO writeback protocol: when a void callback returns undefined, we + // return the original args object so the .NET host can detect property + // mutations made by the callback and apply them back to the original + // C# DTO objects. DTO args are plain JS objects (not Handle wrappers), + // so any property changes the callback made are reflected in args. + // + // Non-void callbacks (result !== undefined) return their actual result. + // The .NET side only activates writeback for void delegates whose + // parameters include [AspireDto] types — all other cases discard the + // returned args object, so the extra wire payload is harmless. + // + // IMPORTANT: callbacks that intentionally return undefined will also + // trigger this path. For non-void delegate types, the C# proxy uses + // a result-unmarshalling path (not writeback), so returning args will + // cause an unmarshal error. Void callbacks should never return a + // meaningful value; non-void callbacks should always return one. + return result !== undefined ? result : args; } - // No positional params found - call with no args + // No positional params found — nothing to write back return await callback(); } diff --git a/src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs b/src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs index 06931ab9b8c..4c35cb505c5 100644 --- a/src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs @@ -44,6 +44,7 @@ public static partial class DevTunnelsResourceBuilderExtensions /// builder.Build().Run(); /// /// + [AspireExport("addDevTunnel", Description = "Adds a Dev Tunnel resource to the distributed application model.")] public static IResourceBuilder AddDevTunnel( this IDistributedApplicationBuilder builder, [ResourceName] string name, @@ -239,6 +240,7 @@ await notifications.PublishUpdateAsync(portResource, snapshot => snapshot with /// The resource builder for the referenced resource. /// Whether anonymous access is allowed. /// The resource builder. + [AspireExport("withReferenceResourceAnonymous", MethodName = "withTunnelReferenceAll", Description = "Configures the dev tunnel to expose all endpoints on the referenced resource.")] public static IResourceBuilder WithReference( this IResourceBuilder tunnelBuilder, IResourceBuilder resourceBuilder, @@ -255,12 +257,14 @@ public static IResourceBuilder WithReference( /// Adds ports on the dev tunnel for all endpoints found on the referenced resource. /// /// + /// This overload is not available in polyglot app hosts. Use the overload that accepts a allowAnonymous parameter instead. /// To expose only specific endpoints on the referenced resource, use . /// /// The resource builder. /// The resource builder for the referenced resource. /// Options for the dev tunnel ports. /// The resource builder. + [AspireExportIgnore(Reason = "DevTunnelPortOptions is not ATS-compatible. Use the overload with bool allowAnonymous parameter instead.")] public static IResourceBuilder WithReference( this IResourceBuilder tunnelBuilder, IResourceBuilder resourceBuilder, @@ -285,6 +289,7 @@ public static IResourceBuilder WithReference( /// The resource builder. /// The endpoint to expose via the dev tunnel. /// The resource builder. + [AspireExport("withReferenceEndpoint", MethodName = "withTunnelReference", Description = "Configures the dev tunnel to expose a target endpoint.")] public static IResourceBuilder WithReference( this IResourceBuilder tunnelBuilder, EndpointReference targetEndpoint) @@ -297,6 +302,7 @@ public static IResourceBuilder WithReference( /// The endpoint to expose via the dev tunnel. /// Whether anonymous access is allowed. /// The resource builder. + [AspireExport("withReferenceEndpointAnonymous", MethodName = "withTunnelReferenceAnonymous", Description = "Configures the dev tunnel to expose a target endpoint with access control.")] public static IResourceBuilder WithReference( this IResourceBuilder tunnelBuilder, EndpointReference targetEndpoint, @@ -306,10 +312,14 @@ public static IResourceBuilder WithReference( /// /// Exposes the specified endpoint via the dev tunnel. /// + /// + /// This overload is not available in polyglot app hosts. Use or instead. + /// /// The resource builder. /// The endpoint to expose via the dev tunnel. /// Options for the dev tunnel port. /// The resource builder. + [AspireExportIgnore(Reason = "DevTunnelPortOptions is not ATS-compatible. Use the overload with EndpointReference or EndpointReference + bool instead.")] public static IResourceBuilder WithReference( this IResourceBuilder tunnelBuilder, EndpointReference targetEndpoint, @@ -331,6 +341,7 @@ public static IResourceBuilder WithReference( /// /// The resource builder. /// The resource builder. + [AspireExport("withAnonymousAccess", Description = "Configures the dev tunnel to allow anonymous access.")] public static IResourceBuilder WithAnonymousAccess(this IResourceBuilder tunnelBuilder) { tunnelBuilder.Resource.Options.AllowAnonymous = true; @@ -340,12 +351,16 @@ public static IResourceBuilder WithAnonymousAccess(this IReso /// /// Gets the tunnel endpoint reference for the specified target resource and endpoint. /// + /// + /// This method is not available in polyglot app hosts. Use instead. + /// /// The type of the target resource. /// The dev tunnel resource builder. /// The target resource builder. /// The name of the endpoint on the target resource. /// An representing the public tunnel endpoint. /// Thrown when the specified endpoint is not found in the tunnel. + [AspireExportIgnore(Reason = "Delegates to the IResource-based overload which is already exported.")] public static EndpointReference GetEndpoint(this IResourceBuilder tunnelBuilder, IResourceBuilder resourceBuilder, string endpointName) where TResource : IResourceWithEndpoints { @@ -359,10 +374,14 @@ public static EndpointReference GetEndpoint(this IResourceBuilder /// Gets the tunnel endpoint reference for the specified target resource and endpoint. /// + /// + /// This method is not available in polyglot app hosts. Use instead. + /// /// The dev tunnel resource builder. /// The target resource. /// The name of the endpoint on the target resource. /// An representing the public tunnel endpoint. + [AspireExportIgnore(Reason = "IResource parameter type is not ATS-compatible. Use the EndpointReference-based overload instead.")] public static EndpointReference GetEndpoint(this IResourceBuilder tunnelBuilder, IResource resource, string endpointName) { ArgumentNullException.ThrowIfNull(tunnelBuilder); @@ -386,6 +405,7 @@ public static EndpointReference GetEndpoint(this IResourceBuilderThe dev tunnel resource builder. /// The target endpoint reference. /// An representing the public tunnel endpoint. + [AspireExport("getEndpointByEndpointReference", MethodName = "getTunnelEndpoint", Description = "Gets the public endpoint exposed by the dev tunnel.")] public static EndpointReference GetEndpoint(this IResourceBuilder tunnelBuilder, EndpointReference targetEndpointReference) { ArgumentNullException.ThrowIfNull(tunnelBuilder); @@ -418,11 +438,13 @@ private static EndpointReference CreateEndpointReferenceWithError(DevTunnelResou /// /// /// Referencing a dev tunnel will delay the start of the resource until the referenced dev tunnel's endpoint is allocated. + /// This method is not available in polyglot app hosts. /// /// The builder. /// The resource to inject service discovery information for. /// The dev tunnel resource to resolve the tunnel address from. /// The builder. + [AspireExportIgnore(Reason = "This method extends generic IResourceBuilder and injects dev tunnel service discovery. It requires two IResourceBuilder parameters which makes the polyglot API confusing. Use WithReference on the DevTunnelResource builder instead.")] public static IResourceBuilder WithReference(this IResourceBuilder builder, IResourceBuilder targetResource, IResourceBuilder tunnelResource) where TResource : IResourceWithEnvironment diff --git a/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs b/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs index 29940acac4e..1b6ab9f5ca1 100644 --- a/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs +++ b/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs @@ -51,6 +51,8 @@ public static class GarnetBuilderExtensions /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. /// The host port to bind the underlying container to. /// A reference to the . + /// This overload is not available in polyglot app hosts. Use instead. + [AspireExportIgnore(Reason = "Use the dedicated polyglot overload instead.")] public static IResourceBuilder AddGarnet(this IDistributedApplicationBuilder builder, [ResourceName] string name, int? port) { @@ -94,6 +96,8 @@ public static IResourceBuilder AddGarnet(this IDistributedApplic /// The host port to bind the underlying container to. /// The parameter used to provide the password for the Redis resource. If a random password will be generated. /// A reference to the . + /// This overload is not available in polyglot app hosts. Use instead. + [AspireExportIgnore(Reason = "Use the dedicated polyglot overload instead.")] public static IResourceBuilder AddGarnet(this IDistributedApplicationBuilder builder, [ResourceName] string name, int? port = null, IResourceBuilder? password = null) { @@ -170,6 +174,14 @@ public static IResourceBuilder AddGarnet(this IDistributedApplic }); } + [AspireExport("addGarnet", Description = "Adds a Garnet container resource to the application model.")] + internal static IResourceBuilder AddGarnetForPolyglot( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + int? port = null, + IResourceBuilder? password = null) + => AddGarnet(builder, name, port, password); + /// /// Adds a named volume for the data folder to a Garnet container resource and enables Garnet persistence. /// @@ -190,6 +202,7 @@ public static IResourceBuilder AddGarnet(this IDistributedApplic /// Defaults to false. /// /// The . + [AspireExport("withDataVolume", Description = "Adds a persistent data volume to the Garnet resource.")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) { @@ -225,6 +238,7 @@ public static IResourceBuilder WithDataVolume(this IResourceBuil /// Defaults to false. /// /// The . + [AspireExport("withDataBindMount", Description = "Mounts a host directory as the Garnet data directory.")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) { @@ -278,6 +292,7 @@ public static IResourceBuilder WithPersistence(this IResourceBui /// The resource builder. /// The interval between snapshot exports. Defaults to 60 seconds. /// The . + [AspireExport("withPersistence", Description = "Configures snapshot persistence for the Garnet resource.")] public static IResourceBuilder WithPersistence(this IResourceBuilder builder, TimeSpan? interval = null) { diff --git a/src/Aspire.Hosting.GitHub.Models/GitHubModel.Generated.cs b/src/Aspire.Hosting.GitHub.Models/GitHubModel.Generated.cs index 32d0c14987f..d685f4a0be5 100644 --- a/src/Aspire.Hosting.GitHub.Models/GitHubModel.Generated.cs +++ b/src/Aspire.Hosting.GitHub.Models/GitHubModel.Generated.cs @@ -269,4 +269,276 @@ public static partial class XAI /// public static readonly GitHubModel Grok3Mini = new() { Id = "xai/grok-3-mini" }; } + + /// + /// Gets the model identifier string for the specified . + /// + internal static string GetModelId(GitHubModelName name) => name switch + { + GitHubModelName.AI21Jamba15Large => "ai21-labs/ai21-jamba-1.5-large", + GitHubModelName.CohereCommandA => "cohere/cohere-command-a", + GitHubModelName.CohereCommandR082024 => "cohere/cohere-command-r-08-2024", + GitHubModelName.CohereCommandRPlus082024 => "cohere/cohere-command-r-plus-08-2024", + GitHubModelName.DeepSeekR1 => "deepseek/deepseek-r1", + GitHubModelName.DeepSeekR10528 => "deepseek/deepseek-r1-0528", + GitHubModelName.DeepSeekV30324 => "deepseek/deepseek-v3-0324", + GitHubModelName.Llama4Maverick17B128EInstructFP8 => "meta/llama-4-maverick-17b-128e-instruct-fp8", + GitHubModelName.Llama4Scout17B16EInstruct => "meta/llama-4-scout-17b-16e-instruct", + GitHubModelName.Llama3211BVisionInstruct => "meta/llama-3.2-11b-vision-instruct", + GitHubModelName.Llama3290BVisionInstruct => "meta/llama-3.2-90b-vision-instruct", + GitHubModelName.Llama3370BInstruct => "meta/llama-3.3-70b-instruct", + GitHubModelName.MetaLlama31405BInstruct => "meta/meta-llama-3.1-405b-instruct", + GitHubModelName.MetaLlama318BInstruct => "meta/meta-llama-3.1-8b-instruct", + GitHubModelName.MaiDSR1 => "microsoft/mai-ds-r1", + GitHubModelName.Phi4 => "microsoft/phi-4", + GitHubModelName.Phi4MiniInstruct => "microsoft/phi-4-mini-instruct", + GitHubModelName.Phi4MiniReasoning => "microsoft/phi-4-mini-reasoning", + GitHubModelName.Phi4MultimodalInstruct => "microsoft/phi-4-multimodal-instruct", + GitHubModelName.Phi4Reasoning => "microsoft/phi-4-reasoning", + GitHubModelName.Codestral2501 => "mistral-ai/codestral-2501", + GitHubModelName.Ministral3B => "mistral-ai/ministral-3b", + GitHubModelName.MistralMedium32505 => "mistral-ai/mistral-medium-2505", + GitHubModelName.MistralSmall31 => "mistral-ai/mistral-small-2503", + GitHubModelName.OpenAIGpt41 => "openai/gpt-4.1", + GitHubModelName.OpenAIGpt41Mini => "openai/gpt-4.1-mini", + GitHubModelName.OpenAIGpt41Nano => "openai/gpt-4.1-nano", + GitHubModelName.OpenAIGpt4o => "openai/gpt-4o", + GitHubModelName.OpenAIGpt4oMini => "openai/gpt-4o-mini", + GitHubModelName.OpenAIGpt5 => "openai/gpt-5", + GitHubModelName.OpenAIGpt5ChatPreview => "openai/gpt-5-chat", + GitHubModelName.OpenAIGpt5Mini => "openai/gpt-5-mini", + GitHubModelName.OpenAIGpt5Nano => "openai/gpt-5-nano", + GitHubModelName.OpenAIO1 => "openai/o1", + GitHubModelName.OpenAIO1Mini => "openai/o1-mini", + GitHubModelName.OpenAIO1Preview => "openai/o1-preview", + GitHubModelName.OpenAIO3 => "openai/o3", + GitHubModelName.OpenAIO3Mini => "openai/o3-mini", + GitHubModelName.OpenAIO4Mini => "openai/o4-mini", + GitHubModelName.OpenAITextEmbedding3Large => "openai/text-embedding-3-large", + GitHubModelName.OpenAITextEmbedding3Small => "openai/text-embedding-3-small", + GitHubModelName.Grok3 => "xai/grok-3", + GitHubModelName.Grok3Mini => "xai/grok-3-mini", + _ => throw new System.ArgumentOutOfRangeException(nameof(name), name, "Unknown GitHub model name.") + }; +} + +/// +/// Enumerates known GitHub model names for polyglot app host support. +/// +internal enum GitHubModelName +{ + /// + /// A 398B parameters (94B active) multilingual model, offering a 256K long context window, function calling, structured output, and grounded generation. + /// + AI21Jamba15Large, + + /// + /// Command A is a highly efficient generative model that excels at agentic and multilingual use cases. + /// + CohereCommandA, + + /// + /// Command R is a scalable generative model targeting RAG and Tool Use to enable production-scale AI for enterprise. + /// + CohereCommandR082024, + + /// + /// Command R+ is a state-of-the-art RAG-optimized model designed to tackle enterprise-grade workloads. + /// + CohereCommandRPlus082024, + + /// + /// DeepSeek-R1 excels at reasoning tasks using a step-by-step training process, such as language, scientific reasoning, and coding tasks. + /// + DeepSeekR1, + + /// + /// The DeepSeek R1 0528 model has improved reasoning capabilities, this version also offers a reduced hallucination rate, enhanced support for function calling, and better experience for vibe coding. + /// + DeepSeekR10528, + + /// + /// DeepSeek-V3-0324 demonstrates notable improvements over its predecessor, DeepSeek-V3, in several key aspects, including enhanced reasoning, improved function calling, and superior code generation capabilities. + /// + DeepSeekV30324, + + /// + /// Llama 4 Maverick 17B 128E Instruct FP8 is great at precise image understanding and creative writing, offering high quality at a lower price compared to Llama 3.3 70B + /// + Llama4Maverick17B128EInstructFP8, + + /// + /// Llama 4 Scout 17B 16E Instruct is great at multi-document summarization, parsing extensive user activity for personalized tasks, and reasoning over vast codebases. + /// + Llama4Scout17B16EInstruct, + + /// + /// Excels in image reasoning capabilities on high-res images for visual understanding apps. + /// + Llama3211BVisionInstruct, + + /// + /// Advanced image reasoning capabilities for visual understanding agentic apps. + /// + Llama3290BVisionInstruct, + + /// + /// Llama 3.3 70B Instruct offers enhanced reasoning, math, and instruction following with performance comparable to Llama 3.1 405B. + /// + Llama3370BInstruct, + + /// + /// The Llama 3.1 instruction tuned text only models are optimized for multilingual dialogue use cases and outperform many of the available open source and closed chat models on common industry benchmarks. + /// + MetaLlama31405BInstruct, + + /// + /// The Llama 3.1 instruction tuned text only models are optimized for multilingual dialogue use cases and outperform many of the available open source and closed chat models on common industry benchmarks. + /// + MetaLlama318BInstruct, + + /// + /// MAI-DS-R1 is a DeepSeek-R1 reasoning model that has been post-trained by the Microsoft AI team to fill in information gaps in the previous version of the model and improve its harm protections while maintaining R1 reasoning capabilities. + /// + MaiDSR1, + + /// + /// Phi-4 14B, a highly capable model for low latency scenarios. + /// + Phi4, + + /// + /// 3.8B parameters Small Language Model outperforming larger models in reasoning, math, coding, and function-calling + /// + Phi4MiniInstruct, + + /// + /// Lightweight math reasoning model optimized for multi-step problem solving + /// + Phi4MiniReasoning, + + /// + /// First small multimodal model to have 3 modality inputs (text, audio, image), excelling in quality and efficiency + /// + Phi4MultimodalInstruct, + + /// + /// State-of-the-art open-weight reasoning model. + /// + Phi4Reasoning, + + /// + /// Codestral 25.01 by Mistral AI is designed for code generation, supporting 80+ programming languages, and optimized for tasks like code completion and fill-in-the-middle + /// + Codestral2501, + + /// + /// Ministral 3B is a state-of-the-art Small Language Model (SLM) optimized for edge computing and on-device applications. As it is designed for low-latency and compute-efficient inference, it it also the perfect model for standard GenAI applications that have + /// + Ministral3B, + + /// + /// Mistral Medium 3 is an advanced Large Language Model (LLM) with state-of-the-art reasoning, knowledge, coding and vision capabilities. + /// + MistralMedium32505, + + /// + /// Enhanced Mistral Small 3 with multimodal capabilities and a 128k context length. + /// + MistralSmall31, + + /// + /// gpt-4.1 outperforms gpt-4o across the board, with major gains in coding, instruction following, and long-context understanding + /// + OpenAIGpt41, + + /// + /// gpt-4.1-mini outperform gpt-4o-mini across the board, with major gains in coding, instruction following, and long-context handling + /// + OpenAIGpt41Mini, + + /// + /// gpt-4.1-nano provides gains in coding, instruction following, and long-context handling along with lower latency and cost + /// + OpenAIGpt41Nano, + + /// + /// OpenAI's most advanced multimodal model in the gpt-4o family. Can handle both text and image inputs. + /// + OpenAIGpt4o, + + /// + /// An affordable, efficient AI solution for diverse text and image tasks. + /// + OpenAIGpt4oMini, + + /// + /// gpt-5 is designed for logic-heavy and multi-step tasks. + /// + OpenAIGpt5, + + /// + /// gpt-5-chat (preview) is an advanced, natural, multimodal, and context-aware conversations for enterprise applications. + /// + OpenAIGpt5ChatPreview, + + /// + /// gpt-5-mini is a lightweight version for cost-sensitive applications. + /// + OpenAIGpt5Mini, + + /// + /// gpt-5-nano is optimized for speed, ideal for applications requiring low latency. + /// + OpenAIGpt5Nano, + + /// + /// Focused on advanced reasoning and solving complex problems, including math and science tasks. Ideal for applications that require deep contextual understanding and agentic workflows. + /// + OpenAIO1, + + /// + /// Smaller, faster, and 80% cheaper than o1-preview, performs well at code generation and small context operations. + /// + OpenAIO1Mini, + + /// + /// Focused on advanced reasoning and solving complex problems, including math and science tasks. Ideal for applications that require deep contextual understanding and agentic workflows. + /// + OpenAIO1Preview, + + /// + /// o3 includes significant improvements on quality and safety while supporting the existing features of o1 and delivering comparable or better performance. + /// + OpenAIO3, + + /// + /// o3-mini includes the o1 features with significant cost-efficiencies for scenarios requiring high performance. + /// + OpenAIO3Mini, + + /// + /// o4-mini includes significant improvements on quality and safety while supporting the existing features of o3-mini and delivering comparable or better performance. + /// + OpenAIO4Mini, + + /// + /// Text-embedding-3 series models are the latest and most capable embedding model from OpenAI. + /// + OpenAITextEmbedding3Large, + + /// + /// Text-embedding-3 series models are the latest and most capable embedding model from OpenAI. + /// + OpenAITextEmbedding3Small, + + /// + /// Grok 3 is xAI's debut model, pretrained by Colossus at supermassive scale to excel in specialized domains like finance, healthcare, and the law. + /// + Grok3, + + /// + /// Grok 3 Mini is a lightweight model that thinks before responding. Trained on mathematic and scientific problems, it is great for logic-based tasks. + /// + Grok3Mini, } diff --git a/src/Aspire.Hosting.GitHub.Models/GitHubModelsExtensions.cs b/src/Aspire.Hosting.GitHub.Models/GitHubModelsExtensions.cs index 9d773343182..65138394114 100644 --- a/src/Aspire.Hosting.GitHub.Models/GitHubModelsExtensions.cs +++ b/src/Aspire.Hosting.GitHub.Models/GitHubModelsExtensions.cs @@ -22,6 +22,7 @@ public static class GitHubModelsExtensions /// The model name to use with GitHub Models. /// The organization login associated with the organization to which the request is to be attributed. /// A reference to the . + [AspireExportIgnore(Reason = "The polyglot overload uses the GitHubModelName enum instead. See the internal AddGitHubModel(GitHubModelName) overload.")] public static IResourceBuilder AddGitHubModel(this IDistributedApplicationBuilder builder, [ResourceName] string name, string model, IResourceBuilder? organization = null) { ArgumentNullException.ThrowIfNull(builder); @@ -88,6 +89,7 @@ await evt.Eventing.PublishAsync(new ConnectionStringAvailableEvent(r, evt.Servic /// The organization login associated with the organization to which the request is to be attributed. /// A reference to the . /// + /// This overload is not available in polyglot app hosts. Use the string-based overload instead. /// /// Create a GitHub Model resource for the Microsoft Phi-3 Medium Instruct model: /// @@ -97,6 +99,7 @@ await evt.Eventing.PublishAsync(new ConnectionStringAvailableEvent(r, evt.Servic /// /// /// + [AspireExportIgnore(Reason = "GitHubModel is a .NET-specific descriptor type not compatible with ATS. Use the GitHubModelName enum-based overload instead.")] public static IResourceBuilder AddGitHubModel(this IDistributedApplicationBuilder builder, [ResourceName] string name, GitHubModel model, IResourceBuilder? organization = null) { ArgumentNullException.ThrowIfNull(model); @@ -104,6 +107,34 @@ public static IResourceBuilder AddGitHubModel(this IDistrib return AddGitHubModel(builder, name, model.Id, organization); } + /// + /// Adds a GitHub Model resource to the application model using a known . + /// + /// The . + /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. + /// The known model name from the enumeration. + /// The organization login associated with the organization to which the request is to be attributed. + /// A reference to the . + [AspireExport("addGitHubModel", Description = "Adds a GitHub Model resource to the distributed application model.")] + internal static IResourceBuilder AddGitHubModel(this IDistributedApplicationBuilder builder, [ResourceName] string name, GitHubModelName model, IResourceBuilder? organization = null) + { + return AddGitHubModel(builder, name, GitHubModel.GetModelId(model), organization); + } + + /// + /// Adds a GitHub Model resource to the application model using a model identifier string. + /// + /// The . + /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. + /// The model identifier string, for example "openai/gpt-4o". + /// The organization login associated with the organization to which the request is to be attributed. + /// A reference to the . + [AspireExport("addGitHubModelById", Description = "Adds a GitHub Model resource using a model identifier string.")] + internal static IResourceBuilder AddGitHubModelById(this IDistributedApplicationBuilder builder, [ResourceName] string name, string modelId, IResourceBuilder? organization = null) + { + return AddGitHubModel(builder, name, modelId, organization); + } + /// /// Configures the API key for the GitHub Model resource from a parameter. /// @@ -111,6 +142,7 @@ public static IResourceBuilder AddGitHubModel(this IDistrib /// The API key parameter. /// The resource builder. /// Thrown when the provided parameter is not marked as secret. + [AspireExport("withApiKey", Description = "Configures the API key for the GitHub Model resource.")] public static IResourceBuilder WithApiKey(this IResourceBuilder builder, IResourceBuilder apiKey) { ArgumentNullException.ThrowIfNull(builder); @@ -153,6 +185,7 @@ public static IResourceBuilder WithApiKey(this IResourceBui /// the model is not working as expected. Furthermore, the health check will run a single time per application instance. /// /// + [AspireExport("enableHealthCheck", Description = "Adds a health check for the GitHub Model resource.")] public static IResourceBuilder WithHealthCheck(this IResourceBuilder builder) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.GitHub.Models/tools/GenModel.cs b/src/Aspire.Hosting.GitHub.Models/tools/GenModel.cs index 782e30dbf56..e3c79a9aa29 100644 --- a/src/Aspire.Hosting.GitHub.Models/tools/GenModel.cs +++ b/src/Aspire.Hosting.GitHub.Models/tools/GenModel.cs @@ -15,12 +15,6 @@ var ghCode = GitHubModelClassGenerator.GenerateCode("Aspire.Hosting.GitHub", ghModels); File.WriteAllText(Path.Combine("..", "GitHubModel.Generated.cs"), ghCode); Console.WriteLine("Generated GitHub model descriptors written to GitHubModel.Generated.cs"); -Console.WriteLine("\nGitHub Model data:"); -Console.WriteLine(JsonSerializer.Serialize(ghModels, new JsonSerializerOptions -{ - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull -})); public sealed class GitHubModel { @@ -82,8 +76,11 @@ public static string GenerateCode(string ns, List models) sb.AppendLine("/// "); sb.AppendLine("public partial class GitHubModel"); sb.AppendLine("{"); - var groups = models.Where(m => !string.IsNullOrEmpty(m.Publisher) && !string.IsNullOrEmpty(m.Name)) - .GroupBy(m => m.Publisher) + var validModels = models.Where(m => !string.IsNullOrEmpty(m.Publisher) && !string.IsNullOrEmpty(m.Name)) + .OrderBy(m => m.Publisher, StringComparer.OrdinalIgnoreCase) + .ThenBy(m => m.Name, StringComparer.OrdinalIgnoreCase) + .ToList(); + var groups = validModels.GroupBy(m => m.Publisher) .OrderBy(g => g.Key, StringComparer.OrdinalIgnoreCase); var firstClass = true; foreach (var g in groups) @@ -121,6 +118,47 @@ public static string GenerateCode(string ns, List models) } sb.AppendLine(" }"); } + sb.AppendLine(); + + // Generate internal conversion method + sb.AppendLine(" /// "); + sb.AppendLine(" /// Gets the model identifier string for the specified ."); + sb.AppendLine(" /// "); + sb.AppendLine(" internal static string GetModelId(GitHubModelName name) => name switch"); + sb.AppendLine(" {"); + foreach (var m in validModels) + { + var prop = ToPascalCase(m.Name); + sb.AppendLine(CultureInfo.InvariantCulture, $" GitHubModelName.{prop} => \"{Esc(m.Id)}\","); + } + sb.AppendLine(" _ => throw new System.ArgumentOutOfRangeException(nameof(name), name, \"Unknown GitHub model name.\")"); + sb.AppendLine(" };"); + sb.AppendLine("}"); + sb.AppendLine(); + + // Generate internal enum + sb.AppendLine("/// "); + sb.AppendLine("/// Enumerates known GitHub model names for polyglot app host support."); + sb.AppendLine("/// "); + sb.AppendLine("internal enum GitHubModelName"); + sb.AppendLine("{"); + var firstEnum = true; + foreach (var m in validModels) + { + if (!firstEnum) + { + sb.AppendLine(); + } + + firstEnum = false; + + var prop = ToPascalCase(m.Name); + var desc = EscapeXml(Clean(m.Summary ?? $"Descriptor for {m.Name}")); + sb.AppendLine(" /// "); + sb.AppendLine(CultureInfo.InvariantCulture, $" /// {desc}"); + sb.AppendLine(" /// "); + sb.AppendLine(CultureInfo.InvariantCulture, $" {prop},"); + } sb.AppendLine("}"); return sb.ToString(); } diff --git a/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs b/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs index 4e86970b0d7..ea355141d51 100644 --- a/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs +++ b/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs @@ -38,6 +38,7 @@ public static class MilvusBuilderExtensions /// The parameter used to provide the auth key/token user for the Milvus resource. /// The host port of gRPC endpoint of Milvus database. /// A reference to the . + [AspireExport("addMilvus", Description = "Adds a Milvus server resource to the distributed application model.")] public static IResourceBuilder AddMilvus(this IDistributedApplicationBuilder builder, string name, IResourceBuilder? apiKey = null, @@ -92,6 +93,7 @@ public static IResourceBuilder AddMilvus(this IDistributed /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. /// The name of the database. If not provided, this defaults to the same value as . /// A reference to the . + [AspireExport("addDatabase", Description = "Adds a Milvus database resource to a Milvus server resource.")] public static IResourceBuilder AddDatabase(this IResourceBuilder builder, [ResourceName] string name, string? databaseName = null) { ArgumentNullException.ThrowIfNull(builder); @@ -128,6 +130,7 @@ public static IResourceBuilder AddDatabase(this IResourc /// Configuration callback for Attu container resource. /// The name of the container (Optional). /// A reference to the . + [AspireExport("withAttu", Description = "Adds the Attu administration tool for Milvus.")] public static IResourceBuilder WithAttu(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null) where T : MilvusServerResource { ArgumentNullException.ThrowIfNull(builder); @@ -154,6 +157,7 @@ public static IResourceBuilder WithAttu(this IResourceBuilder builder, /// The name of the volume. Defaults to an auto-generated name based on the resource name. /// A flag that indicates if this is a read-only volume. /// The . + [AspireExport("withDataVolume", Description = "Adds a persistent data volume to the Milvus server resource.")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); @@ -168,6 +172,7 @@ public static IResourceBuilder WithDataVolume(this IResour /// The source directory on the host to mount into the container. /// A flag that indicates if this is a read-only mount. /// The . + [AspireExport("withDataBindMount", Description = "Mounts a host directory as the Milvus data directory.")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); @@ -197,6 +202,7 @@ public static IResourceBuilder WithConfigurationBindMount( /// The resource builder. /// The configuration file on the host to copy into the container. /// The . + [AspireExport("withConfigurationFile", Description = "Copies a Milvus configuration file into the container.")] public static IResourceBuilder WithConfigurationFile(this IResourceBuilder builder, string configurationFilePath) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.MySql/MySqlBuilderExtensions.cs b/src/Aspire.Hosting.MySql/MySqlBuilderExtensions.cs index 280f9eed279..b1eb5cc91c9 100644 --- a/src/Aspire.Hosting.MySql/MySqlBuilderExtensions.cs +++ b/src/Aspire.Hosting.MySql/MySqlBuilderExtensions.cs @@ -31,6 +31,7 @@ public static class MySqlBuilderExtensions /// The parameter used to provide the root password for the MySQL resource. If a random password will be generated. /// The host port for MySQL. /// A reference to the . + [AspireExport("addMySql", Description = "Adds a MySQL server resource")] public static IResourceBuilder AddMySql(this IDistributedApplicationBuilder builder, [ResourceName] string name, IResourceBuilder? password = null, int? port = null) { ArgumentNullException.ThrowIfNull(builder); @@ -108,6 +109,7 @@ public static IResourceBuilder AddMySql(this IDistributedAp /// The database creation happens automatically as part of the resource lifecycle. /// /// + [AspireExport("addDatabase", Description = "Adds a MySQL database")] public static IResourceBuilder AddDatabase(this IResourceBuilder builder, [ResourceName] string name, string? databaseName = null) { ArgumentNullException.ThrowIfNull(builder); @@ -181,6 +183,7 @@ private static async Task CreateDatabaseAsync(MySqlConnection sqlConnection, MyS /// /// Default script is CREATE DATABASE IF NOT EXISTS `QUOTED_DATABASE_NAME`; /// + [AspireExport("withCreationScript", Description = "Defines the SQL script for database creation")] public static IResourceBuilder WithCreationScript(this IResourceBuilder builder, string script) { ArgumentNullException.ThrowIfNull(builder); @@ -197,6 +200,7 @@ public static IResourceBuilder WithCreationScript(this IR /// The resource builder. /// The parameter used to provide the password for the MySQL resource. /// The . + [AspireExport("withPassword", Description = "Configures the MySQL password")] public static IResourceBuilder WithPassword(this IResourceBuilder builder, IResourceBuilder password) { ArgumentNullException.ThrowIfNull(builder); @@ -216,6 +220,7 @@ public static IResourceBuilder WithPassword(this IResourceB /// Callback to configure PhpMyAdmin container resource. /// The name of the container (Optional). /// A reference to the . + [AspireExport("withPhpMyAdmin", Description = "Adds phpMyAdmin management UI")] public static IResourceBuilder WithPhpMyAdmin(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null) where T : MySqlServerResource { ArgumentNullException.ThrowIfNull(builder); @@ -304,6 +309,7 @@ public static IResourceBuilder WithPhpMyAdmin(this IResourceBuilder bui /// The resource builder for PGAdmin. /// The port to bind on the host. If is used, a random port will be assigned. /// The resource builder for PGAdmin. + [AspireExport("withHostPort", Description = "Sets the host port for phpMyAdmin")] public static IResourceBuilder WithHostPort(this IResourceBuilder builder, int? port) { ArgumentNullException.ThrowIfNull(builder); @@ -321,6 +327,7 @@ public static IResourceBuilder WithHostPort(this IR /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// A flag that indicates if this is a read-only volume. /// The . + [AspireExport("withDataVolume", Description = "Adds a data volume for MySQL")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); @@ -335,6 +342,7 @@ public static IResourceBuilder WithDataVolume(this IResourc /// The source directory on the host to mount into the container. /// A flag that indicates if this is a read-only mount. /// The . + [AspireExport("withDataBindMount", Description = "Adds a data bind mount for MySQL")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); @@ -365,6 +373,7 @@ public static IResourceBuilder WithInitBindMount(this IReso /// The resource builder. /// The source file or directory on the host to copy into the container. /// The . + [AspireExport("withInitFiles", Description = "Copies init files to MySQL")] public static IResourceBuilder WithInitFiles(this IResourceBuilder builder, string source) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.Nats/NatsBuilderExtensions.cs b/src/Aspire.Hosting.Nats/NatsBuilderExtensions.cs index 13286d56b52..30cb5d640ff 100644 --- a/src/Aspire.Hosting.Nats/NatsBuilderExtensions.cs +++ b/src/Aspire.Hosting.Nats/NatsBuilderExtensions.cs @@ -27,6 +27,8 @@ public static class NatsBuilderExtensions /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. /// The host port for NATS server. /// The . + /// This overload is not available in polyglot app hosts. Use instead. + [AspireExportIgnore(Reason = "Use the dedicated polyglot overload instead.")] public static IResourceBuilder AddNats(this IDistributedApplicationBuilder builder, [ResourceName] string name, int? port) { return AddNats(builder, name, port, null); @@ -41,9 +43,11 @@ public static IResourceBuilder AddNats(this IDistributedAppl /// The . /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. /// The host port for NATS server. - /// The parameter used to provide the user name for the PostgreSQL resource. If a default value will be used. - /// The parameter used to provide the administrator password for the PostgreSQL resource. If a random password will be generated. + /// The parameter used to provide the user name for the NATS resource. If a default value will be used. + /// The parameter used to provide the administrator password for the NATS resource. If a random password will be generated. /// The . + /// This overload is not available in polyglot app hosts. Use instead. + [AspireExportIgnore(Reason = "Use the dedicated polyglot overload instead.")] public static IResourceBuilder AddNats(this IDistributedApplicationBuilder builder, [ResourceName] string name, int? port = null, IResourceBuilder? userName = null, IResourceBuilder? password = null) @@ -103,6 +107,15 @@ public static IResourceBuilder AddNats(this IDistributedAppl }); } + [AspireExport("addNats", Description = "Adds a NATS server resource to the application model.")] + internal static IResourceBuilder AddNatsForPolyglot( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + int? port = null, + IResourceBuilder? userName = null, + IResourceBuilder? password = null) + => AddNats(builder, name, port, userName, password); + /// /// Adds JetStream support to the NATS server resource. /// @@ -130,6 +143,7 @@ public static IResourceBuilder WithJetStream(this IResourceB /// /// The resource builder. /// The . + [AspireExport("withJetStream", Description = "Configures the NATS resource to enable JetStream.")] public static IResourceBuilder WithJetStream(this IResourceBuilder builder) { ArgumentNullException.ThrowIfNull(builder); @@ -144,6 +158,7 @@ public static IResourceBuilder WithJetStream(this IResourceB /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// A flag that indicates if this is a read-only volume. /// The . + [AspireExport("withDataVolume", Description = "Adds a persistent data volume to the NATS resource.")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); @@ -160,6 +175,7 @@ public static IResourceBuilder WithDataVolume(this IResource /// The source directory on the host to mount into the container. /// A flag that indicates if this is a read-only mount. /// The . + [AspireExport("withDataBindMount", Description = "Mounts a host directory as the NATS data directory.")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.OpenAI/OpenAIExtensions.cs b/src/Aspire.Hosting.OpenAI/OpenAIExtensions.cs index a79bbdd6554..a659af67241 100644 --- a/src/Aspire.Hosting.OpenAI/OpenAIExtensions.cs +++ b/src/Aspire.Hosting.OpenAI/OpenAIExtensions.cs @@ -19,6 +19,7 @@ public static class OpenAIExtensions /// The . /// The name of the OpenAI resource. /// The OpenAI resource builder. + [AspireExport("addOpenAI", Description = "Adds an OpenAI resource to the distributed application model.")] public static IResourceBuilder AddOpenAI(this IDistributedApplicationBuilder builder, [ResourceName] string name) { ArgumentNullException.ThrowIfNull(builder); @@ -99,6 +100,7 @@ await evt.Eventing.PublishAsync(new ConnectionStringAvailableEvent(r, evt.Servic /// The name of the model resource. This name is used as the connection string name. /// The model identifier, e.g., "gpt-4o-mini". /// The model resource builder. + [AspireExport("addModel", Description = "Adds an OpenAI model resource.")] public static IResourceBuilder AddModel(this IResourceBuilder builder, [ResourceName] string name, string model) { ArgumentNullException.ThrowIfNull(builder); @@ -139,6 +141,7 @@ await evt.Eventing.PublishAsync(new ConnectionStringAvailableEvent(r, evt.Servic /// /// The OpenAI parent resource builder. /// The endpoint URI, e.g., https://mygateway.example.com/v1. + [AspireExport("withEndpoint", Description = "Configures the endpoint URI for the OpenAI resource.")] public static IResourceBuilder WithEndpoint(this IResourceBuilder builder, string endpoint) { ArgumentNullException.ThrowIfNull(builder); @@ -151,6 +154,7 @@ public static IResourceBuilder WithEndpoint(this IResourceBuilde /// /// Configures the API key for the OpenAI parent resource from a parameter. /// + [AspireExport("withApiKey", Description = "Configures the API key for the OpenAI resource.")] public static IResourceBuilder WithApiKey(this IResourceBuilder builder, IResourceBuilder apiKey) { ArgumentNullException.ThrowIfNull(builder); @@ -193,6 +197,7 @@ public static IResourceBuilder WithApiKey(this IResourceBuilder< /// the model is not working as expected. Furthermore, the health check will run a single time per application instance. /// /// + [AspireExport("withHealthCheck", Description = "Adds a health check for the OpenAI model resource.")] public static IResourceBuilder WithHealthCheck(this IResourceBuilder builder) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.Oracle/OracleDatabaseBuilderExtensions.cs b/src/Aspire.Hosting.Oracle/OracleDatabaseBuilderExtensions.cs index c2a372fceae..8bc678a04bd 100644 --- a/src/Aspire.Hosting.Oracle/OracleDatabaseBuilderExtensions.cs +++ b/src/Aspire.Hosting.Oracle/OracleDatabaseBuilderExtensions.cs @@ -25,6 +25,7 @@ public static class OracleDatabaseBuilderExtensions /// The parameter used to provide the administrator password for the Oracle Server resource. If a random password will be generated. /// The host port for Oracle Server. /// A reference to the . + [AspireExport("addOracle", Description = "Adds an Oracle server resource to the distributed application model.")] public static IResourceBuilder AddOracle( this IDistributedApplicationBuilder builder, [ResourceName] string name, @@ -73,6 +74,7 @@ public static IResourceBuilder AddOracle( /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. /// The name of the database. If not provided, this defaults to the same value as . /// A reference to the . + [AspireExport("addDatabase", Description = "Adds an Oracle database resource to an Oracle server resource.")] public static IResourceBuilder AddDatabase( this IResourceBuilder builder, [ResourceName] string name, @@ -95,6 +97,7 @@ public static IResourceBuilder AddDatabase( /// The resource builder. /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// The . + [AspireExport("withDataVolume", Description = "Adds a persistent data volume to the Oracle server resource.")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null) { ArgumentNullException.ThrowIfNull(builder); @@ -108,6 +111,7 @@ public static IResourceBuilder WithDataVolume(this /// The resource builder. /// The source directory on the host to mount into the container. /// The . + [AspireExport("withDataBindMount", Description = "Mounts a host directory as the Oracle data directory.")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source) { ArgumentNullException.ThrowIfNull(builder); @@ -137,6 +141,7 @@ public static IResourceBuilder WithInitBindMount(t /// The resource builder. /// The source file or directory on the host to copy into the container. /// The . + [AspireExport("withInitFiles", Description = "Copies initialization files into the Oracle container.")] public static IResourceBuilder WithInitFiles(this IResourceBuilder builder, string source) { ArgumentNullException.ThrowIfNull(builder); @@ -155,6 +160,7 @@ public static IResourceBuilder WithInitFiles(this /// The resource builder. /// The source directory on the host to mount into the container. /// The . + [AspireExport("withDbSetupBindMount", Description = "Mounts a host directory as the Oracle DB setup directory.")] public static IResourceBuilder WithDbSetupBindMount(this IResourceBuilder builder, string source) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs b/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs index edac4585b83..1c9ae4488b5 100644 --- a/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs +++ b/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs @@ -14,6 +14,7 @@ namespace Aspire.Hosting.ApplicationModel; /// The database name. /// The Oracle Database parent resource associated with this database. [DebuggerDisplay("Type = {GetType().Name,nq}, Name = {Name}, Database = {DatabaseName}")] +[AspireExport(ExposeProperties = true)] public class OracleDatabaseResource(string name, string databaseName, OracleDatabaseServerResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString { @@ -25,6 +26,8 @@ public class OracleDatabaseResource(string name, string databaseName, OracleData /// /// Gets the connection string expression for the Oracle Database. /// + /// This property is not available in polyglot app hosts. + [AspireExportIgnore] public ReferenceExpression ConnectionStringExpression => ReferenceExpression.Create($"{Parent}/{DatabaseName}"); diff --git a/src/Aspire.Hosting.Oracle/OracleDatabaseServerResource.cs b/src/Aspire.Hosting.Oracle/OracleDatabaseServerResource.cs index c2a8072ad89..96f48442da9 100644 --- a/src/Aspire.Hosting.Oracle/OracleDatabaseServerResource.cs +++ b/src/Aspire.Hosting.Oracle/OracleDatabaseServerResource.cs @@ -6,6 +6,7 @@ namespace Aspire.Hosting.ApplicationModel; /// /// A resource that represents an Oracle Database container. /// +[AspireExport(ExposeProperties = true)] public class OracleDatabaseServerResource : ContainerResource, IResourceWithConnectionString { internal const string PrimaryEndpointName = "tcp"; @@ -47,6 +48,8 @@ public OracleDatabaseServerResource(string name, ParameterResource password) : b /// /// Gets the connection string expression for the Oracle Database server. /// + /// This property is not available in polyglot app hosts. + [AspireExportIgnore] public ReferenceExpression ConnectionStringExpression => ReferenceExpression.Create( $"user id={DefaultUserName};password={PasswordParameter};data source={PrimaryEndpoint.Property(EndpointProperty.HostAndPort)}"); diff --git a/src/Aspire.Hosting.Qdrant/QdrantBuilderExtensions.cs b/src/Aspire.Hosting.Qdrant/QdrantBuilderExtensions.cs index 295ba8ac2e3..7c5c713f97a 100644 --- a/src/Aspire.Hosting.Qdrant/QdrantBuilderExtensions.cs +++ b/src/Aspire.Hosting.Qdrant/QdrantBuilderExtensions.cs @@ -34,6 +34,7 @@ public static class QdrantBuilderExtensions /// The host port of gRPC endpoint of Qdrant database. /// The host port of HTTP endpoint of Qdrant database. /// A reference to the . + [AspireExport("addQdrant", Description = "Adds a Qdrant resource to the application. A container is used for local development.")] public static IResourceBuilder AddQdrant(this IDistributedApplicationBuilder builder, string name, IResourceBuilder? apiKey = null, @@ -104,6 +105,7 @@ public static IResourceBuilder AddQdrant(this IDistributed /// The name of the volume. Defaults to an auto-generated name based on the resource name. /// A flag that indicates if this is a read-only volume. /// The . + [AspireExport("withDataVolume", Description = "Adds a named volume for the data folder to a Qdrant container resource.")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); @@ -119,6 +121,7 @@ public static IResourceBuilder WithDataVolume(this IResour /// The source directory on the host to mount into the container. /// A flag that indicates if this is a read-only mount. /// The . + [AspireExport("withDataBindMount", Description = "Adds a bind mount for the data folder to a Qdrant container resource.")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.RemoteHost/Ats/AtsCallbackProxyFactory.cs b/src/Aspire.Hosting.RemoteHost/Ats/AtsCallbackProxyFactory.cs index 330398558b3..d07037ed45f 100644 --- a/src/Aspire.Hosting.RemoteHost/Ats/AtsCallbackProxyFactory.cs +++ b/src/Aspire.Hosting.RemoteHost/Ats/AtsCallbackProxyFactory.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; +using System.Diagnostics; using System.Linq.Expressions; using System.Reflection; using System.Text.Json.Nodes; @@ -93,7 +94,9 @@ private Delegate BuildProxy(string callbackId, Type delegateType) { if (!hasResult) { - body = BuildAsyncVoidCall(callbackId, argsExpr, ctExpr); + body = HasDtoParameters(parameters) + ? BuildAsyncVoidCallWithDtoWriteback(callbackId, argsExpr, ctExpr, paramExprs, parameters) + : BuildAsyncVoidCall(callbackId, argsExpr, ctExpr); } else { @@ -104,7 +107,9 @@ private Delegate BuildProxy(string callbackId, Type delegateType) { if (!hasResult) { - body = BuildSyncVoidCall(callbackId, argsExpr, ctExpr); + body = HasDtoParameters(parameters) + ? BuildSyncVoidCallWithDtoWriteback(callbackId, argsExpr, ctExpr, paramExprs, parameters) + : BuildSyncVoidCall(callbackId, argsExpr, ctExpr); } else { @@ -231,6 +236,13 @@ private void InvokeSyncVoid(string callbackId, JsonObject? args, CancellationTok _invoker.InvokeAsync(callbackId, args, cancellationToken).GetAwaiter().GetResult(); } + private void InvokeSyncVoidWithDtoWriteback(string callbackId, JsonObject? args, object?[] originalArgs, Type[] argTypes, CancellationToken cancellationToken) + { + AddCancellationTokenToArgs(ref args, cancellationToken); + var result = _invoker.InvokeAsync(callbackId, args, cancellationToken).GetAwaiter().GetResult(); + ApplyDtoWriteback(result, originalArgs, argTypes); + } + private T? InvokeSyncResult(string callbackId, JsonObject? args, CancellationToken cancellationToken) { AddCancellationTokenToArgs(ref args, cancellationToken); @@ -244,6 +256,13 @@ private async Task InvokeAsyncVoid(string callbackId, JsonObject? args, Cancella await _invoker.InvokeAsync(callbackId, args, cancellationToken).ConfigureAwait(false); } + private async Task InvokeAsyncVoidWithDtoWriteback(string callbackId, JsonObject? args, object?[] originalArgs, Type[] argTypes, CancellationToken cancellationToken) + { + AddCancellationTokenToArgs(ref args, cancellationToken); + var result = await _invoker.InvokeAsync(callbackId, args, cancellationToken).ConfigureAwait(false); + ApplyDtoWriteback(result, originalArgs, argTypes); + } + private async Task InvokeAsyncResult(string callbackId, JsonObject? args, CancellationToken cancellationToken) { AddCancellationTokenToArgs(ref args, cancellationToken); @@ -277,6 +296,108 @@ private void AddCancellationTokenToArgs(ref JsonObject? args, CancellationToken } } + private bool HasDtoParameters(ParameterInfo[] parameters) + { + return parameters.Any(p => + p.ParameterType != typeof(CancellationToken) && + _marshaller.IsDtoType(p.ParameterType)); + } + + private Expression BuildSyncVoidCallWithDtoWriteback(string callbackId, Expression? argsExpr, Expression? ctExpr, ParameterExpression[] paramExprs, ParameterInfo[] parameters) + { + var (originalsExpr, typesExpr) = BuildOriginalArgsArrays(paramExprs, parameters); + + var invokeMethod = typeof(AtsCallbackProxyFactory).GetMethod( + nameof(InvokeSyncVoidWithDtoWriteback), + BindingFlags.Instance | BindingFlags.NonPublic)!; + + return Expression.Call( + Expression.Constant(this), + invokeMethod, + Expression.Constant(callbackId), + argsExpr ?? Expression.Constant(null, typeof(JsonObject)), + originalsExpr, + typesExpr, + ctExpr ?? Expression.Constant(CancellationToken.None, typeof(CancellationToken))); + } + + private Expression BuildAsyncVoidCallWithDtoWriteback(string callbackId, Expression? argsExpr, Expression? ctExpr, ParameterExpression[] paramExprs, ParameterInfo[] parameters) + { + var (originalsExpr, typesExpr) = BuildOriginalArgsArrays(paramExprs, parameters); + + var invokeMethod = typeof(AtsCallbackProxyFactory).GetMethod( + nameof(InvokeAsyncVoidWithDtoWriteback), + BindingFlags.Instance | BindingFlags.NonPublic)!; + + return Expression.Call( + Expression.Constant(this), + invokeMethod, + Expression.Constant(callbackId), + argsExpr ?? Expression.Constant(null, typeof(JsonObject)), + originalsExpr, + typesExpr, + ctExpr ?? Expression.Constant(CancellationToken.None, typeof(CancellationToken))); + } + + private static (Expression Originals, Expression Types) BuildOriginalArgsArrays(ParameterExpression[] paramExprs, ParameterInfo[] parameters) + { + var nonCtParams = new List<(ParameterExpression Expr, Type Type)>(); + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].ParameterType != typeof(CancellationToken)) + { + nonCtParams.Add((paramExprs[i], parameters[i].ParameterType)); + } + } + + var originalsExpr = Expression.NewArrayInit(typeof(object), + nonCtParams.Select(p => Expression.Convert(p.Expr, typeof(object)))); + + var typesExpr = Expression.NewArrayInit(typeof(Type), + nonCtParams.Select(p => (Expression)Expression.Constant(p.Type, typeof(Type)))); + + return (originalsExpr, typesExpr); + } + + private void ApplyDtoWriteback(JsonNode? result, object?[] originalArgs, Type[] argTypes) + { + Debug.Assert(originalArgs.Length == argTypes.Length, "originalArgs and argTypes must have the same length"); + + if (result is not JsonObject returnedArgs) + { + return; + } + + for (int i = 0; i < originalArgs.Length; i++) + { + if (originalArgs[i] is null) + { + continue; + } + + if (!_marshaller.IsDtoType(argTypes[i])) + { + continue; + } + + // Value types (structs) are boxed into the originalArgs array, so mutations + // via ApplyDtoProperties would modify the boxed copy, not the caller's variable. + // Skip writeback for value types to avoid silent no-op behavior. + if (argTypes[i].IsValueType) + { + continue; + } + + // Positional key matches the convention used in BuildMarshalArgs and the + // TypeScript extraction loop in transport.ts registerCallback. + var key = $"p{i}"; + if (returnedArgs[key] is JsonObject modifiedDto) + { + _marshaller.ApplyDtoProperties(modifiedDto, originalArgs[i]!, argTypes[i]); + } + } + } + public void Dispose() { // No-op - CancellationTokenRegistry is managed by DI diff --git a/src/Aspire.Hosting.RemoteHost/Ats/AtsMarshaller.cs b/src/Aspire.Hosting.RemoteHost/Ats/AtsMarshaller.cs index 7f6a3ee66a9..6fb5cff2bd5 100644 --- a/src/Aspire.Hosting.RemoteHost/Ats/AtsMarshaller.cs +++ b/src/Aspire.Hosting.RemoteHost/Ats/AtsMarshaller.cs @@ -6,6 +6,7 @@ using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace Aspire.Hosting.RemoteHost.Ats; @@ -47,11 +48,19 @@ internal sealed class UnmarshalContext public string? ParameterName { get; init; } } + // NOTE: ReferenceHandler.IgnoreCycles prevents JsonException when serializing DTOs + // with circular references (e.g. parent/child back-references). Cycles are broken by + // writing null for back-edges. This means the TypeScript side will receive null for + // cycle-broken properties. During DTO writeback, those null values will overwrite the + // original non-null references on the C# side — this is intentional, since TypeScript + // cannot represent object cycles and the writeback reflects what TypeScript observed. private static readonly JsonSerializerOptions s_jsonOptions = new() { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - Converters = { new JsonStringEnumConverter() } + Converters = { new JsonStringEnumConverter() }, + ReferenceHandler = ReferenceHandler.IgnoreCycles, + TypeInfoResolver = new DefaultJsonTypeInfoResolver() }; /// @@ -528,4 +537,76 @@ public static bool IsSimpleType(Type type) return JsonSerializer.Deserialize(value.ToJsonString(), targetType, s_jsonOptions); } + + /// + /// Checks if a type is a DTO type (marked with [AspireDto] and registered in the context). + /// + /// The type to check. + /// true if the type is a DTO type; otherwise, false. + public bool IsDtoType(Type type) + { + return _context.GetCategory(type) == Hosting.Ats.AtsTypeCategory.Dto; + } + + /// + /// Applies property values from a JSON object to an existing DTO instance. + /// Used for applying mutations made in callbacks back to the original objects. + /// Only writable properties and public fields whose types can be deserialized + /// from the JSON are updated. Properties with complex types that lack a + /// parameterless constructor (e.g. EndpointReference) are silently skipped. + /// + /// The JSON object containing the updated values. + /// The existing DTO instance to update. + /// The CLR type of the target object. + /// + /// + /// Nested DTO properties are deserialized as new instances, not patched in-place. + /// External references to the original nested object will not see the mutations. + /// + /// + /// When ReferenceHandler.IgnoreCycles is active, cycle-broken properties + /// arrive as null and will overwrite the original non-null reference. + /// + /// + // Instance method for consistency with IsDtoType and future extensibility. +#pragma warning disable CA1822 // Member does not access instance data + public void ApplyDtoProperties(JsonObject source, object target, Type targetType) +#pragma warning restore CA1822 + { + // Use JsonTypeInfo metadata instead of raw reflection so that + // [JsonPropertyName], [JsonIgnore], the naming policy, and field + // inclusion configuration are all respected automatically. + var typeInfo = s_jsonOptions.GetTypeInfo(targetType); + + foreach (var prop in typeInfo.Properties) + { + if (prop.Set is null) + { + continue; + } + + if (!source.TryGetPropertyValue(prop.Name, out var jsonValue)) + { + continue; + } + + try + { + prop.Set(target, jsonValue.Deserialize(prop.PropertyType, s_jsonOptions)); + } + catch (NotSupportedException) + { + // Silently skip properties whose types can't be deserialized by + // System.Text.Json (e.g. EndpointReference with no parameterless + // constructor). This is expected for DTO types that carry complex + // navigation properties alongside simple writable data. + } + catch (JsonException) + { + // Silently skip properties where the JSON value is incompatible + // with the CLR property type (e.g. string sent for an int field). + // This is a best-effort writeback — partial updates are acceptable. + } + } + } } diff --git a/src/Aspire.Hosting.RemoteHost/Ats/CapabilityDispatcher.cs b/src/Aspire.Hosting.RemoteHost/Ats/CapabilityDispatcher.cs index 2af40e8523d..73380737594 100644 --- a/src/Aspire.Hosting.RemoteHost/Ats/CapabilityDispatcher.cs +++ b/src/Aspire.Hosting.RemoteHost/Ats/CapabilityDispatcher.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Text.Json; using System.Text.Json.Nodes; +using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Ats; using Microsoft.Extensions.Logging; @@ -169,7 +170,12 @@ private void RegisterContextTypeProperty(AtsCapabilityInfo capability, PropertyI throw CapabilityException.HandleNotFound(handleRef.HandleId, capabilityId); } - var value = prop.GetValue(contextObj); + // Bridge builder -> resource: if the handle contains an IResourceBuilder + // but the property is declared on the resource type T, unwrap to the + // correct target object. See AtsCapabilityScanner.MapToAtsTypeId. + var target = ResolveContextTarget(contextObj!, prop.DeclaringType!); + + var value = prop.GetValue(target); return Task.FromResult(_marshaller.MarshalToJson(value, capability.ReturnType)); }; @@ -212,7 +218,10 @@ private void RegisterContextTypeProperty(AtsCapabilityInfo capability, PropertyI ParameterName = "value" }; var value = _marshaller.UnmarshalFromJson(valueNode, prop.PropertyType, unmarshalContext); - prop.SetValue(contextObj, value); + + // Bridge builder -> resource for setter as well. + var setTarget = ResolveContextTarget(contextObj!, prop.DeclaringType!); + prop.SetValue(setTarget, value); // Return the context handle for fluent chaining return Task.FromResult(new JsonObject @@ -292,11 +301,16 @@ private void RegisterContextTypeMethod(AtsCapabilityInfo capability, MethodInfo methodToInvoke = GenericMethodResolver.MakeGenericMethodFromArgs(method, methodArgs); } + // Bridge builder -> resource: if the handle contains an IResourceBuilder + // but the method is declared on the resource type T, unwrap to the + // correct target object. See AtsCapabilityScanner.MapToAtsTypeId. + var invokeTarget = ResolveContextTarget(contextObj!, methodToInvoke.DeclaringType!); + object? result; try { // Invoke instance method on the context object - result = methodToInvoke.Invoke(contextObj, methodArgs); + result = methodToInvoke.Invoke(invokeTarget, methodArgs); } catch (TargetInvocationException tie) when (tie.InnerException is not null) { @@ -517,6 +531,31 @@ private static bool IsTypeMismatchException(ArgumentException ex) message.Contains("type mismatch", StringComparison.OrdinalIgnoreCase); } + /// + /// Resolves the correct target object for a member invocation. + /// Handles the case where the handle contains an but the + /// member is declared on the resource type T, since + /// AtsCapabilityScanner.MapToAtsTypeId maps both to the same type ID. + /// + private static object ResolveContextTarget(object contextObj, Type declaringType) + { + if (declaringType.IsInstanceOfType(contextObj)) + { + return contextObj; + } + + // Handle is a builder, but the member is on the resource type - extract .Resource + if (contextObj is IResourceBuilder builder && + declaringType.IsInstanceOfType(builder.Resource)) + { + return builder.Resource; + } + + // No bridge matched — return as-is; the CLR will throw TargetException if the + // object truly doesn't match the declaring type. + return contextObj; + } + /// /// Gets all registered capability IDs. /// diff --git a/src/Aspire.Hosting.Seq/SeqBuilderExtensions.cs b/src/Aspire.Hosting.Seq/SeqBuilderExtensions.cs index e7ffc8dd566..51006b70c15 100644 --- a/src/Aspire.Hosting.Seq/SeqBuilderExtensions.cs +++ b/src/Aspire.Hosting.Seq/SeqBuilderExtensions.cs @@ -18,10 +18,12 @@ public static class SeqBuilderExtensions /// /// /// This version of the package defaults to the tag of the container image. + /// This overload is not available in polyglot app hosts. Use instead. /// /// The . /// The name to give the resource. /// The host port for the Seq server. + [AspireExportIgnore(Reason = "Convenience overload. Use the overload with optional adminPassword parameter instead.")] public static IResourceBuilder AddSeq( this IDistributedApplicationBuilder builder, string name, @@ -40,6 +42,7 @@ public static IResourceBuilder AddSeq( /// The name to give the resource. /// The admin password for Seq. If not provided, authentication will be disabled. /// The host port for the Seq server. + [AspireExport("addSeq", Description = "Adds a Seq server container resource")] public static IResourceBuilder AddSeq( this IDistributedApplicationBuilder builder, string name, @@ -76,6 +79,7 @@ public static IResourceBuilder AddSeq( /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// A flag that indicates if this is a read-only volume. /// The . + [AspireExport("withDataVolume", Description = "Adds a data volume for Seq")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); @@ -90,6 +94,7 @@ public static IResourceBuilder WithDataVolume(this IResourceBuilder /// The source directory on the host to mount into the container. /// A flag that indicates if this is a read-only mount. /// The . + [AspireExport("withDataBindMount", Description = "Adds a data bind mount for Seq")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.Valkey/ValkeyBuilderExtensions.cs b/src/Aspire.Hosting.Valkey/ValkeyBuilderExtensions.cs index c01dddd9de1..716f94b193c 100644 --- a/src/Aspire.Hosting.Valkey/ValkeyBuilderExtensions.cs +++ b/src/Aspire.Hosting.Valkey/ValkeyBuilderExtensions.cs @@ -25,6 +25,8 @@ public static class ValkeyBuilderExtensions /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. /// The host port to bind the underlying container to. /// + /// This overload is not available in polyglot app hosts. Use instead. + /// /// /// Use in application host /// @@ -54,6 +56,7 @@ public static class ValkeyBuilderExtensions /// /// A reference to the . /// check this + [AspireExportIgnore(Reason = "Convenience overload. Use the overload with optional password parameter instead.")] public static IResourceBuilder AddValkey( this IDistributedApplicationBuilder builder, [ResourceName] string name, @@ -104,6 +107,7 @@ public static IResourceBuilder AddValkey( /// /// /// A reference to the . + [AspireExport("addValkey", Description = "Adds a Valkey container resource")] public static IResourceBuilder AddValkey( this IDistributedApplicationBuilder builder, [ResourceName] string name, @@ -199,6 +203,7 @@ public static IResourceBuilder AddValkey( /// /// /// The . + [AspireExport("withDataVolume", Description = "Adds a data volume for Valkey and enables persistence")] public static IResourceBuilder WithDataVolume( this IResourceBuilder builder, string? name = null, @@ -236,6 +241,7 @@ public static IResourceBuilder WithDataVolume( /// /// /// The . + [AspireExport("withDataBindMount", Description = "Adds a data bind mount for Valkey and enables persistence")] public static IResourceBuilder WithDataBindMount( this IResourceBuilder builder, string source, @@ -271,6 +277,7 @@ public static IResourceBuilder WithDataBindMount( /// /// /// The . + [AspireExport("withPersistence", Description = "Configures Valkey persistence")] public static IResourceBuilder WithPersistence( this IResourceBuilder builder, TimeSpan? interval = null, diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/IYarpConfigurationBuilder.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/IYarpConfigurationBuilder.cs index 5161980fbd6..52a1549aee5 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/IYarpConfigurationBuilder.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/IYarpConfigurationBuilder.cs @@ -9,6 +9,7 @@ namespace Aspire.Hosting; /// /// Interface to build a configuration file for YARP /// +[AspireExport(ExposeMethods = true)] public interface IYarpConfigurationBuilder { /// diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ForwardedTransformExtensions.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ForwardedTransformExtensions.cs index 952929e3ebd..df908a1c995 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ForwardedTransformExtensions.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ForwardedTransformExtensions.cs @@ -14,6 +14,7 @@ public static class ForwardedTransformExtensions /// /// Adds the transform which will add X-Forwarded-* headers. /// + [AspireExport("withTransformXForwarded", Description = "Adds the transform which will add X-Forwarded-* headers.")] public static YarpRoute WithTransformXForwarded( this YarpRoute route, string headerPrefix = "X-Forwarded-", @@ -30,6 +31,7 @@ public static YarpRoute WithTransformXForwarded( /// /// Adds the transform which will add the Forwarded header as defined by [RFC 7239](https://tools.ietf.org/html/rfc7239). /// + [AspireExport("withTransformForwarded", Description = "Adds the transform which will add the Forwarded header as defined by [RFC 7239](https://tools.ietf.org/html/rfc7239).")] public static YarpRoute WithTransformForwarded(this YarpRoute route, bool useHost = true, bool useProto = true, NodeFormat forFormat = NodeFormat.Random, NodeFormat byFormat = NodeFormat.Random, ForwardedTransformActions action = ForwardedTransformActions.Set) { @@ -40,6 +42,7 @@ public static YarpRoute WithTransformForwarded(this YarpRoute route, bool useHos /// /// Adds the transform which will set the given header with the Base64 encoded client certificate. /// + [AspireExport("withTransformClientCertHeader", Description = "Adds the transform which will set the given header with the Base64 encoded client certificate.")] public static YarpRoute WithTransformClientCertHeader(this YarpRoute route, string headerName) { route.Configure(r => r.WithTransformClientCertHeader(headerName)); diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/HttpMethodTransformExtensions.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/HttpMethodTransformExtensions.cs index 95e6dc940df..fd3d0c36030 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/HttpMethodTransformExtensions.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/HttpMethodTransformExtensions.cs @@ -14,6 +14,7 @@ public static class HttpMethodTransformExtensions /// /// Adds the transform that will replace the HTTP method if it matches. /// + [AspireExport("withTransformHttpMethodChange", Description = "Adds the transform that will replace the HTTP method if it matches.")] public static YarpRoute WithTransformHttpMethodChange(this YarpRoute route, string fromHttpMethod, string toHttpMethod) { route.Configure(r => r.WithTransformHttpMethodChange(fromHttpMethod, toHttpMethod)); diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/PathTransformExtensions.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/PathTransformExtensions.cs index 38e77d264d9..0cb2a676898 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/PathTransformExtensions.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/PathTransformExtensions.cs @@ -16,6 +16,7 @@ public static class PathTransformExtensions /// /// Adds the transform which sets the request path with the given value. /// + [AspireExport("withTransformPathSet", Description = "Adds the transform which sets the request path with the given value.")] public static YarpRoute WithTransformPathSet(this YarpRoute route, PathString path) { if (path.Value is null) @@ -31,6 +32,7 @@ public static YarpRoute WithTransformPathSet(this YarpRoute route, PathString pa /// /// Adds the transform which will prefix the request path with the given value. /// + [AspireExport("withTransformPathPrefix", Description = "Adds the transform which will prefix the request path with the given value.")] public static YarpRoute WithTransformPathPrefix(this YarpRoute route, PathString prefix) { if (prefix.Value is null) @@ -46,6 +48,7 @@ public static YarpRoute WithTransformPathPrefix(this YarpRoute route, PathString /// /// Adds the transform which will remove the matching prefix from the request path. /// + [AspireExport("withTransformPathRemovePrefix", Description = "Adds the transform which will remove the matching prefix from the request path.")] public static YarpRoute WithTransformPathRemovePrefix(this YarpRoute route, PathString prefix) { if (prefix.Value is null) @@ -61,6 +64,7 @@ public static YarpRoute WithTransformPathRemovePrefix(this YarpRoute route, Path /// /// Adds the transform which will set the request path with the given value. /// + [AspireExport("withTransformPathRouteValues", Description = "Adds the transform which will set the request path with the given value.")] public static YarpRoute WithTransformPathRouteValues(this YarpRoute route, [StringSyntax("Route")] PathString pattern) { if (pattern.Value is null) diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/QueryTransformExtensions.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/QueryTransformExtensions.cs index 178541f33ca..e4910dbc2ce 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/QueryTransformExtensions.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/QueryTransformExtensions.cs @@ -14,6 +14,7 @@ public static class QueryTransformExtensions /// /// Adds the transform that will append or set the query parameter from the given value. /// + [AspireExport("withTransformQueryValue", Description = "Adds the transform that will append or set the query parameter from the given value.")] public static YarpRoute WithTransformQueryValue(this YarpRoute route, string queryKey, string value, bool append = true) { route.Configure(r => r.WithTransformQueryValue(queryKey, value, append)); @@ -23,6 +24,7 @@ public static YarpRoute WithTransformQueryValue(this YarpRoute route, string que /// /// Adds the transform that will append or set the query parameter from a route value. /// + [AspireExport("withTransformQueryRouteValue", Description = "Adds the transform that will append or set the query parameter from a route value.")] public static YarpRoute WithTransformQueryRouteValue(this YarpRoute route, string queryKey, string routeValueKey, bool append = true) { route.Configure(r => r.WithTransformQueryRouteValue(queryKey, routeValueKey, append)); @@ -32,6 +34,7 @@ public static YarpRoute WithTransformQueryRouteValue(this YarpRoute route, strin /// /// Adds the transform that will remove the given query key. /// + [AspireExport("withTransformQueryRemoveKey", Description = "Adds the transform that will remove the given query key.")] public static YarpRoute WithTransformQueryRemoveKey(this YarpRoute route, string queryKey) { route.Configure(r => r.WithTransformQueryRemoveKey(queryKey)); diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/RequestHeadersTransformExtensions.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/RequestHeadersTransformExtensions.cs index 6599f0d105e..5a8df8eeed0 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/RequestHeadersTransformExtensions.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/RequestHeadersTransformExtensions.cs @@ -13,6 +13,7 @@ public static class RequestHeadersTransformExtensions /// /// Adds the transform which will enable or suppress copying request headers to the proxy request. /// + [AspireExport("withTransformCopyRequestHeaders", Description = "Adds the transform which will enable or suppress copying request headers to the proxy request.")] public static YarpRoute WithTransformCopyRequestHeaders(this YarpRoute route, bool copy = true) { route.Configure(r => r.WithTransformCopyRequestHeaders(copy)); @@ -22,6 +23,7 @@ public static YarpRoute WithTransformCopyRequestHeaders(this YarpRoute route, bo /// /// Adds the transform which will copy the incoming request Host header to the proxy request. /// + [AspireExport("withTransformUseOriginalHostHeader", Description = "Adds the transform which will copy the incoming request Host header to the proxy request.")] public static YarpRoute WithTransformUseOriginalHostHeader(this YarpRoute route, bool useOriginal = true) { route.Configure(r => r.WithTransformUseOriginalHostHeader(useOriginal)); @@ -31,6 +33,7 @@ public static YarpRoute WithTransformUseOriginalHostHeader(this YarpRoute route, /// /// Adds the transform which will append or set the request header. /// + [AspireExport("withTransformRequestHeader", Description = "Adds the transform which will append or set the request header.")] public static YarpRoute WithTransformRequestHeader(this YarpRoute route, string headerName, string value, bool append = true) { route.Configure(r => r.WithTransformRequestHeader(headerName, value, append)); @@ -40,6 +43,7 @@ public static YarpRoute WithTransformRequestHeader(this YarpRoute route, string /// /// Adds the transform which will append or set the request header from a route value. /// + [AspireExport("withTransformRequestHeaderRouteValue", Description = "Adds the transform which will append or set the request header from a route value.")] public static YarpRoute WithTransformRequestHeaderRouteValue(this YarpRoute route, string headerName, string routeValueKey, bool append = true) { route.Configure(r => r.WithTransformRequestHeaderRouteValue(headerName, routeValueKey, append)); @@ -49,6 +53,7 @@ public static YarpRoute WithTransformRequestHeaderRouteValue(this YarpRoute rout /// /// Adds the transform which will remove the request header. /// + [AspireExport("withTransformRequestHeaderRemove", Description = "Adds the transform which will remove the request header.")] public static YarpRoute WithTransformRequestHeaderRemove(this YarpRoute route, string headerName) { route.Configure(r => r.WithTransformRequestHeaderRemove(headerName)); @@ -59,6 +64,7 @@ public static YarpRoute WithTransformRequestHeaderRemove(this YarpRoute route, s /// Adds the transform which will only copy the allowed request headers. Other transforms /// that modify or append to existing headers may be affected if not included in the allow list. /// + [AspireExport("withTransformRequestHeadersAllowed", Description = "Adds the transform which will only copy the allowed request headers. Other transforms")] public static YarpRoute WithTransformRequestHeadersAllowed(this YarpRoute route, params string[] allowedHeaders) { route.Configure(r => r.WithTransformRequestHeadersAllowed(allowedHeaders)); diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ResponseTransformExtensions.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ResponseTransformExtensions.cs index 67423e45dbd..0c77b82789b 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ResponseTransformExtensions.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/Transforms/ResponseTransformExtensions.cs @@ -13,6 +13,7 @@ public static class ResponseTransformExtensions /// /// Adds the transform which will enable or suppress copying response headers to the client response. /// + [AspireExport("withTransformCopyResponseHeaders", Description = "Adds the transform which will enable or suppress copying response headers to the client response.")] public static YarpRoute WithTransformCopyResponseHeaders(this YarpRoute route, bool copy = true) { route.Configure(r => r.WithTransformCopyResponseHeaders(copy)); @@ -22,6 +23,7 @@ public static YarpRoute WithTransformCopyResponseHeaders(this YarpRoute route, b /// /// Adds the transform which will enable or suppress copying response trailers to the client response. /// + [AspireExport("withTransformCopyResponseTrailers", Description = "Adds the transform which will enable or suppress copying response trailers to the client response.")] public static YarpRoute WithTransformCopyResponseTrailers(this YarpRoute route, bool copy = true) { route.Configure(r => r.WithTransformCopyResponseTrailers(copy)); @@ -31,6 +33,7 @@ public static YarpRoute WithTransformCopyResponseTrailers(this YarpRoute route, /// /// Adds the transform which will append or set the response header. /// + [AspireExport("withTransformResponseHeader", Description = "Adds the transform which will append or set the response header.")] public static YarpRoute WithTransformResponseHeader(this YarpRoute route, string headerName, string value, bool append = true, ResponseCondition condition = ResponseCondition.Success) { route.Configure(r => r.WithTransformResponseHeader(headerName, value, append, condition)); @@ -40,6 +43,7 @@ public static YarpRoute WithTransformResponseHeader(this YarpRoute route, string /// /// Adds the transform which will remove the response header. /// + [AspireExport("withTransformResponseHeaderRemove", Description = "Adds the transform which will remove the response header.")] public static YarpRoute WithTransformResponseHeaderRemove(this YarpRoute route, string headerName, ResponseCondition condition = ResponseCondition.Success) { route.Configure(r => r.WithTransformResponseHeaderRemove(headerName, condition)); @@ -50,6 +54,7 @@ public static YarpRoute WithTransformResponseHeaderRemove(this YarpRoute route, /// Adds the transform which will only copy the allowed response headers. Other transforms /// that modify or append to existing headers may be affected if not included in the allow list. /// + [AspireExport("withTransformResponseHeadersAllowed", Description = "Adds the transform which will only copy the allowed response headers. Other transforms")] public static YarpRoute WithTransformResponseHeadersAllowed(this YarpRoute route, params string[] allowedHeaders) { route.Configure(r => r.WithTransformResponseHeadersAllowed(allowedHeaders)); @@ -59,6 +64,7 @@ public static YarpRoute WithTransformResponseHeadersAllowed(this YarpRoute route /// /// Adds the transform which will append or set the response trailer. /// + [AspireExport("withTransformResponseTrailer", Description = "Adds the transform which will append or set the response trailer.")] public static YarpRoute WithTransformResponseTrailer(this YarpRoute route, string headerName, string value, bool append = true, ResponseCondition condition = ResponseCondition.Success) { route.Configure(r => r.WithTransformResponseTrailer(headerName, value, append, condition)); @@ -68,6 +74,7 @@ public static YarpRoute WithTransformResponseTrailer(this YarpRoute route, strin /// /// Adds the transform which will remove the response trailer. /// + [AspireExport("withTransformResponseTrailerRemove", Description = "Adds the transform which will remove the response trailer.")] public static YarpRoute WithTransformResponseTrailerRemove(this YarpRoute route, string headerName, ResponseCondition condition = ResponseCondition.Success) { route.Configure(r => r.WithTransformResponseTrailerRemove(headerName, condition)); @@ -78,6 +85,7 @@ public static YarpRoute WithTransformResponseTrailerRemove(this YarpRoute route, /// Adds the transform which will only copy the allowed response trailers. Other transforms /// that modify or append to existing trailers may be affected if not included in the allow list. /// + [AspireExport("withTransformResponseTrailersAllowed", Description = "Adds the transform which will only copy the allowed response trailers. Other transforms")] public static YarpRoute WithTransformResponseTrailersAllowed(this YarpRoute route, params string[] allowedHeaders) { route.Configure(r => r.WithTransformResponseTrailersAllowed(allowedHeaders)); diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpCluster.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpCluster.cs index c42c0e97117..b0de6fb5642 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpCluster.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpCluster.cs @@ -10,6 +10,7 @@ namespace Aspire.Hosting.Yarp; /// /// Represents a cluster for YARP routes /// +[AspireExport] public class YarpCluster { // Testing only diff --git a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpRoute.cs b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpRoute.cs index abf916bc369..f3e896ff044 100644 --- a/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpRoute.cs +++ b/src/Aspire.Hosting.Yarp/ConfigurationBuilder/YarpRoute.cs @@ -8,6 +8,7 @@ namespace Aspire.Hosting.Yarp; /// /// Represents a route for YARP /// +[AspireExport] public class YarpRoute { // Testing only diff --git a/src/Aspire.Hosting.Yarp/YarpResourceExtensions.cs b/src/Aspire.Hosting.Yarp/YarpResourceExtensions.cs index a18336933a8..8710a508105 100644 --- a/src/Aspire.Hosting.Yarp/YarpResourceExtensions.cs +++ b/src/Aspire.Hosting.Yarp/YarpResourceExtensions.cs @@ -26,6 +26,7 @@ public static class YarpResourceExtensions /// The . /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. /// A reference to the . + [AspireExport("addYarp", Description = "Adds a YARP container to the application model.")] public static IResourceBuilder AddYarp( this IDistributedApplicationBuilder builder, [ResourceName] string name) @@ -102,6 +103,7 @@ public static IResourceBuilder AddYarp( /// /// The YARP resource to configure. /// The delegate to configure YARP. + [AspireExport("withConfiguration", Description = "Configure the YARP resource.")] public static IResourceBuilder WithConfiguration(this IResourceBuilder builder, Action configurationBuilder) { var configBuilder = new YarpConfigurationBuilder(builder); @@ -114,6 +116,7 @@ public static IResourceBuilder WithConfiguration(this IResourceBui /// /// The resource builder for YARP. /// The port to bind on the host. If is used random port will be assigned. + [AspireExport("withHostPort", Description = "Configures the host port that the YARP resource is exposed on instead of using randomly assigned port.")] public static IResourceBuilder WithHostPort(this IResourceBuilder builder, int? port) { ArgumentNullException.ThrowIfNull(builder); @@ -131,6 +134,7 @@ public static IResourceBuilder WithHostPort(this IResourceBuilder< /// The resource builder for YARP. /// The port to bind on the host. If is used random port will be assigned. /// The updated resource builder. + [AspireExport("withHostHttpsPort", Description = "Configures the host HTTPS port that the YARP resource is exposed on instead of using randomly assigned port.")] public static IResourceBuilder WithHostHttpsPort(this IResourceBuilder builder, int? port) { ArgumentNullException.ThrowIfNull(builder); @@ -145,6 +149,7 @@ public static IResourceBuilder WithHostHttpsPort(this IResourceBui /// /// The resource builder for YARP. /// The . + [AspireExport("withStaticFiles1", MethodName = "withStaticFiles", Description = "Enables static file serving in the YARP resource. Static files are served from the wwwroot folder.")] public static IResourceBuilder WithStaticFiles(this IResourceBuilder builder) { ArgumentNullException.ThrowIfNull(builder); @@ -160,6 +165,7 @@ public static IResourceBuilder WithStaticFiles(this IResourceBuild /// The resource builder for YARP. /// The source path containing static files to serve. /// The . + [AspireExport("withStaticFiles2", MethodName = "withStaticFiles", Description = "Enables static file serving. In run mode: bind mounts to /wwwroot.")] public static IResourceBuilder WithStaticFiles(this IResourceBuilder builder, string sourcePath) { ArgumentNullException.ThrowIfNull(builder); @@ -194,6 +200,7 @@ COPY . /app/wwwroot /// The resource builder for YARP. /// The resource with container files. /// The updated resource builder. + [AspireExport("publishWithStaticFiles", Description = "In publish mode, generates a Dockerfile that copies static files from the specified resource into /app/wwwroot.")] public static IResourceBuilder PublishWithStaticFiles(this IResourceBuilder builder, IResourceBuilder resourceWithFiles) { if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode) diff --git a/src/Aspire.Hosting/ApplicationModel/KnownResourceCommands.cs b/src/Aspire.Hosting/ApplicationModel/KnownResourceCommands.cs index a651b6852b7..db6603a5bc9 100644 --- a/src/Aspire.Hosting/ApplicationModel/KnownResourceCommands.cs +++ b/src/Aspire.Hosting/ApplicationModel/KnownResourceCommands.cs @@ -13,17 +13,17 @@ public static class KnownResourceCommands /// /// The command name for starting a resource. /// - public static readonly string StartCommand = "resource-start"; + public static readonly string StartCommand = "start"; /// /// The command name for stopping a resource. /// - public static readonly string StopCommand = "resource-stop"; + public static readonly string StopCommand = "stop"; /// /// The command name for restarting a resource. /// - public static readonly string RestartCommand = "resource-restart"; + public static readonly string RestartCommand = "restart"; /// /// The command name for setting a parameter value. @@ -34,4 +34,8 @@ public static class KnownResourceCommands /// The command name for deleting a parameter value. /// public static readonly string DeleteParameterCommand = "parameter-delete"; + + internal const string LegacyStartCommand = "resource-start"; + internal const string LegacyStopCommand = "resource-stop"; + internal const string LegacyRestartCommand = "resource-restart"; } diff --git a/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs b/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs index 416a878e18d..2446ae63797 100644 --- a/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs +++ b/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs @@ -10,6 +10,16 @@ namespace Aspire.Hosting.ApplicationModel; /// public class ResourceCommandService { + /// + /// Maps legacy command names to their current equivalents for backwards compatibility. + /// + private static readonly Dictionary s_legacyCommandNameMap = new(StringComparer.OrdinalIgnoreCase) + { + [KnownResourceCommands.LegacyStartCommand] = KnownResourceCommands.StartCommand, + [KnownResourceCommands.LegacyStopCommand] = KnownResourceCommands.StopCommand, + [KnownResourceCommands.LegacyRestartCommand] = KnownResourceCommands.RestartCommand, + }; + private readonly ResourceNotificationService _resourceNotificationService; private readonly ResourceLoggerService _resourceLoggerService; private readonly IServiceProvider _serviceProvider; @@ -124,6 +134,19 @@ internal async Task ExecuteCommandCoreAsync(string resourc logger.LogInformation("Executing command '{CommandName}'.", commandName); var annotation = resource.Annotations.OfType().SingleOrDefault(a => a.Name == commandName); + + // Backwards compatibility: if the command wasn't found and the caller used a legacy name + // (e.g. "resource-start"), fall back to the current name (e.g. "start"). + if (annotation is null && s_legacyCommandNameMap.TryGetValue(commandName, out var mappedName)) + { + logger.LogDebug("Command '{CommandName}' not found, falling back to '{MappedName}'.", commandName, mappedName); + annotation = resource.Annotations.OfType().SingleOrDefault(a => a.Name == mappedName); + if (annotation is not null) + { + commandName = mappedName; + } + } + if (annotation != null) { try diff --git a/src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs b/src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs index eb84f2a5778..5ce4e52f3be 100644 --- a/src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs +++ b/src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs @@ -271,7 +271,7 @@ internal sealed class ExecuteResourceCommandRequest public required string ResourceName { get; init; } /// - /// Gets the command name (e.g., "resource-start", "resource-stop", "resource-restart"). + /// Gets the command name (e.g., "start", "stop", "restart"). /// public required string CommandName { get; init; } } @@ -739,7 +739,7 @@ public string? Type internal sealed class ResourceSnapshotCommand { /// - /// Gets the command name (e.g., "resource-start", "resource-stop", "resource-restart"). + /// Gets the command name (e.g., "start", "stop", "restart"). /// public required string Name { get; init; } diff --git a/tests/Aspire.Cli.EndToEnd.Tests/ProjectReferenceTests.cs b/tests/Aspire.Cli.EndToEnd.Tests/ProjectReferenceTests.cs new file mode 100644 index 00000000000..169a918f438 --- /dev/null +++ b/tests/Aspire.Cli.EndToEnd.Tests/ProjectReferenceTests.cs @@ -0,0 +1,232 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using Aspire.Cli.EndToEnd.Tests.Helpers; +using Aspire.Cli.Tests.Utils; +using Hex1b.Automation; +using Xunit; + +namespace Aspire.Cli.EndToEnd.Tests; + +/// +/// End-to-end test for polyglot project reference support. +/// Creates a .NET hosting integration project and a TypeScript AppHost that references it +/// via settings.json, then verifies the integration is discovered, code-generated, and functional. +/// +public sealed class ProjectReferenceTests(ITestOutputHelper output) +{ + [Fact] + public async Task TypeScriptAppHostWithProjectReferenceIntegration() + { + var workspace = TemporaryWorkspace.Create(output); + + var prNumber = CliE2ETestHelpers.GetRequiredPrNumber(); + var commitSha = CliE2ETestHelpers.GetRequiredCommitSha(); + var isCI = CliE2ETestHelpers.IsRunningInCI; + using var terminal = CliE2ETestHelpers.CreateTestTerminal(); + + var pendingRun = terminal.RunAsync(TestContext.Current.CancellationToken); + + var waitingForAppHostCreated = new CellPatternSearcher() + .Find("Created apphost.ts"); + + var waitForStartSuccess = new CellPatternSearcher() + .Find("AppHost started successfully."); + + // Pattern to verify our custom integration was code-generated + var waitForAddMyServiceInCodegen = new CellPatternSearcher() + .Find("addMyService"); + + // Pattern to verify the resource appears in describe output + var waitForMyServiceInDescribe = new CellPatternSearcher() + .Find("my-svc"); + + var counter = new SequenceCounter(); + var sequenceBuilder = new Hex1bTerminalInputSequenceBuilder(); + + sequenceBuilder.PrepareEnvironment(workspace, counter); + + if (isCI) + { + sequenceBuilder.InstallAspireBundleFromPullRequest(prNumber, counter); + sequenceBuilder.SourceAspireBundleEnvironment(counter); + sequenceBuilder.VerifyAspireCliVersion(commitSha, counter); + } + + // Step 1: Create a TypeScript AppHost (so we get the sdkVersion in settings.json) + sequenceBuilder + .Type("aspire init --language typescript --non-interactive") + .Enter() + .WaitUntil(s => waitingForAppHostCreated.Search(s).Count > 0, TimeSpan.FromMinutes(2)) + .WaitForSuccessPrompt(counter); + + // Step 2: Create the integration project, update settings.json, and modify apphost.ts + sequenceBuilder.ExecuteCallback(() => + { + var workDir = workspace.WorkspaceRoot.FullName; + + // Read the sdkVersion from the settings.json that aspire init created + var settingsPath = Path.Combine(workDir, ".aspire", "settings.json"); + var settingsJson = File.ReadAllText(settingsPath); + using var doc = JsonDocument.Parse(settingsJson); + var sdkVersion = doc.RootElement.GetProperty("sdkVersion").GetString()!; + + // Create the .NET hosting integration project + var integrationDir = Path.Combine(workDir, "MyIntegration"); + Directory.CreateDirectory(integrationDir); + + File.WriteAllText(Path.Combine(integrationDir, "MyIntegration.csproj"), $$""" + + + net10.0 + $(NoWarn);ASPIREATS001 + + + + + + """); + + // Write a nuget.config in the workspace root so MyIntegration.csproj can resolve + // Aspire.Hosting from the configured channel's package source (hive or feed). + // Without this, NuGet walks up from MyIntegration/ and finds no config pointing + // to the hive, falling back to nuget.org which doesn't have prerelease versions. + var aspireHome = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".aspire"); + var hivesDir = Path.Combine(aspireHome, "hives"); + if (Directory.Exists(hivesDir)) + { + var hiveDirs = Directory.GetDirectories(hivesDir); + var sourceLines = new List { """""" }; + foreach (var hiveDir in hiveDirs) + { + var packagesDir = Path.Combine(hiveDir, "packages"); + if (Directory.Exists(packagesDir)) + { + var hiveName = Path.GetFileName(hiveDir); + sourceLines.Insert(0, $""""""); + } + } + var nugetConfig = $""" + + + + + {string.Join("\n ", sourceLines)} + + + """; + File.WriteAllText(Path.Combine(workDir, "nuget.config"), nugetConfig); + } + + File.WriteAllText(Path.Combine(integrationDir, "MyIntegrationExtensions.cs"), """ + using Aspire.Hosting; + using Aspire.Hosting.ApplicationModel; + + namespace Aspire.Hosting; + + public static class MyIntegrationExtensions + { + [AspireExport("addMyService")] + public static IResourceBuilder AddMyService( + this IDistributedApplicationBuilder builder, string name) + => builder.AddContainer(name, "redis", "latest"); + } + """); + + // Update settings.json to add the project reference + using var settingsDoc = JsonDocument.Parse(settingsJson); + var settings = new Dictionary(); + foreach (var prop in settingsDoc.RootElement.EnumerateObject()) + { + settings[prop.Name] = prop.Value.Clone(); + } + settings["packages"] = new Dictionary + { + ["MyIntegration"] = "./MyIntegration/MyIntegration.csproj" + }; + + var updatedJson = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(settingsPath, updatedJson); + + // Delete the generated .modules folder to force re-codegen with the new integration + var modulesDir = Path.Combine(workDir, ".modules"); + if (Directory.Exists(modulesDir)) + { + Directory.Delete(modulesDir, recursive: true); + } + + // Update apphost.ts to use the custom integration + File.WriteAllText(Path.Combine(workDir, "apphost.ts"), """ + import { createBuilder } from './.modules/aspire.js'; + + const builder = await createBuilder(); + await builder.addMyService("my-svc"); + await builder.build().run(); + """); + }); + + // Step 3: Start the AppHost (triggers project ref build + codegen) + // Detect either success or failure + var waitForStartFailure = new CellPatternSearcher() + .Find("AppHost failed to build"); + + sequenceBuilder + .Type("aspire start --non-interactive 2>&1 | tee /tmp/aspire-start-output.txt") + .Enter() + .WaitUntil(s => + { + if (waitForStartFailure.Search(s).Count > 0) + { + // Dump child logs before failing + return true; + } + return waitForStartSuccess.Search(s).Count > 0; + }, TimeSpan.FromMinutes(2)) + .WaitForSuccessPrompt(counter); + + // If start failed, dump the child log for debugging before the test fails + sequenceBuilder + .Type("CHILD_LOG=$(ls -t ~/.aspire/logs/cli_*detach*.log 2>/dev/null | head -1) && if [ -n \"$CHILD_LOG\" ]; then echo '=== CHILD LOG ==='; cat \"$CHILD_LOG\"; echo '=== END CHILD LOG ==='; fi") + .Enter() + .WaitForSuccessPrompt(counter, TimeSpan.FromSeconds(10)); + + // Step 4: Verify the custom integration was code-generated + sequenceBuilder + .Type("grep addMyService .modules/aspire.ts") + .Enter() + .WaitUntil(s => waitForAddMyServiceInCodegen.Search(s).Count > 0, TimeSpan.FromSeconds(5)) + .WaitForSuccessPrompt(counter); + + // Step 5: Wait for the custom resource to be up + sequenceBuilder + .Type("aspire wait my-svc --timeout 60") + .Enter() + .WaitForSuccessPrompt(counter, TimeSpan.FromSeconds(90)); + + // Step 6: Verify the resource appears in describe + sequenceBuilder + .Type("aspire describe my-svc --format json > /tmp/my-svc-describe.json") + .Enter() + .WaitForSuccessPrompt(counter, TimeSpan.FromSeconds(15)) + .Type("cat /tmp/my-svc-describe.json") + .Enter() + .WaitUntil(s => waitForMyServiceInDescribe.Search(s).Count > 0, TimeSpan.FromSeconds(5)) + .WaitForSuccessPrompt(counter); + + // Step 7: Clean up + sequenceBuilder + .Type("aspire stop") + .Enter() + .WaitForSuccessPrompt(counter) + .Type("exit") + .Enter(); + + var sequence = sequenceBuilder.Build(); + + await sequence.ApplyAsync(terminal, TestContext.Current.CancellationToken); + + await pendingRun; + } +} diff --git a/tests/Aspire.Cli.Tests/Backchannel/ResourceSnapshotMapperTests.cs b/tests/Aspire.Cli.Tests/Backchannel/ResourceSnapshotMapperTests.cs index 23c7ab8ae95..e7d4351e9cf 100644 --- a/tests/Aspire.Cli.Tests/Backchannel/ResourceSnapshotMapperTests.cs +++ b/tests/Aspire.Cli.Tests/Backchannel/ResourceSnapshotMapperTests.cs @@ -23,8 +23,8 @@ public void MapToResourceJson_WithPopulatedProperties_MapsCorrectly() ], Commands = [ - new ResourceSnapshotCommand { Name = "resource-stop", State = "Enabled", Description = "Stop" }, - new ResourceSnapshotCommand { Name = "resource-start", State = "Disabled", Description = "Start" } + new ResourceSnapshotCommand { Name = "stop", State = "Enabled", Description = "Stop" }, + new ResourceSnapshotCommand { Name = "start", State = "Disabled", Description = "Start" } ], EnvironmentVariables = [ @@ -45,7 +45,7 @@ public void MapToResourceJson_WithPopulatedProperties_MapsCorrectly() // Only enabled commands should be included Assert.Single(result.Commands!); - Assert.True(result.Commands!.ContainsKey("resource-stop")); + Assert.True(result.Commands!.ContainsKey("stop")); // Only IsFromSpec environment variables should be included Assert.Single(result.Environment!); diff --git a/tests/Aspire.Cli.Tests/Commands/ConfigCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/ConfigCommandTests.cs index 8bd2d2fab37..c18b2b42547 100644 --- a/tests/Aspire.Cli.Tests/Commands/ConfigCommandTests.cs +++ b/tests/Aspire.Cli.Tests/Commands/ConfigCommandTests.cs @@ -419,6 +419,186 @@ public void ShowDeprecatedPackages_DefaultsToFalse() var featureFlags = provider.GetRequiredService(); Assert.False(featureFlags.IsFeatureEnabled(KnownFeatures.ShowDeprecatedPackages, defaultValue: false)); } + + [Fact] + public async Task ConfigSetCommand_WithColonNotation_CreatesNestedObject() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + var result = command.Parse("config set features:polyglotSupportEnabled true"); + + var exitCode = await result.InvokeAsync().DefaultTimeout(); + Assert.Equal(0, exitCode); + + // Colon notation should be normalized to nested JSON, not stored as a flat key + var settingsPath = Path.Combine(workspace.WorkspaceRoot.FullName, ".aspire", "settings.json"); + var json = await File.ReadAllTextAsync(settingsPath); + var settings = JsonNode.Parse(json)?.AsObject(); + Assert.NotNull(settings); + + // Should be stored as nested object, not as flat "features:polyglotSupportEnabled" key + Assert.False(settings.ContainsKey("features:polyglotSupportEnabled")); + Assert.True(settings["features"] is JsonObject); + var featuresObject = settings["features"]!.AsObject(); + Assert.Equal("true", featuresObject["polyglotSupportEnabled"]?.ToString()); + } + + [Fact] + public async Task ConfigSetCommand_ColonThenDot_NoDuplicateKeys() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + + // Set with colon notation first + var result1 = command.Parse("config set features:polyglotSupportEnabled true"); + var exitCode1 = await result1.InvokeAsync().DefaultTimeout(); + Assert.Equal(0, exitCode1); + + // Then set with dot notation + var result2 = command.Parse("config set features.polyglotSupportEnabled false"); + var exitCode2 = await result2.InvokeAsync().DefaultTimeout(); + Assert.Equal(0, exitCode2); + + // Should have a single nested entry, no flat colon key + var settingsPath = Path.Combine(workspace.WorkspaceRoot.FullName, ".aspire", "settings.json"); + var json = await File.ReadAllTextAsync(settingsPath); + var settings = JsonNode.Parse(json)?.AsObject(); + Assert.NotNull(settings); + + Assert.False(settings.ContainsKey("features:polyglotSupportEnabled")); + Assert.True(settings["features"] is JsonObject); + var featuresObject = settings["features"]!.AsObject(); + Assert.Equal("false", featuresObject["polyglotSupportEnabled"]?.ToString()); + } + + [Fact] + public async Task ConfigSetCommand_DotThenColon_NoDuplicateKeys() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + + // Set with dot notation first + var result1 = command.Parse("config set features.polyglotSupportEnabled true"); + var exitCode1 = await result1.InvokeAsync().DefaultTimeout(); + Assert.Equal(0, exitCode1); + + // Then set with colon notation + var result2 = command.Parse("config set features:polyglotSupportEnabled false"); + var exitCode2 = await result2.InvokeAsync().DefaultTimeout(); + Assert.Equal(0, exitCode2); + + // Should have a single nested entry, no flat colon key + var settingsPath = Path.Combine(workspace.WorkspaceRoot.FullName, ".aspire", "settings.json"); + var json = await File.ReadAllTextAsync(settingsPath); + var settings = JsonNode.Parse(json)?.AsObject(); + Assert.NotNull(settings); + + Assert.False(settings.ContainsKey("features:polyglotSupportEnabled")); + Assert.True(settings["features"] is JsonObject); + var featuresObject = settings["features"]!.AsObject(); + Assert.Equal("false", featuresObject["polyglotSupportEnabled"]?.ToString()); + } + + [Fact] + public async Task ConfigDeleteCommand_WithColonNotation_DeletesNestedValue() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + + // Set with dot notation + var setResult = command.Parse("config set features.polyglotSupportEnabled true"); + var setExitCode = await setResult.InvokeAsync().DefaultTimeout(); + Assert.Equal(0, setExitCode); + + // Delete with colon notation + var deleteResult = command.Parse("config delete features:polyglotSupportEnabled"); + var deleteExitCode = await deleteResult.InvokeAsync().DefaultTimeout(); + Assert.Equal(0, deleteExitCode); + + // Verify the entire features structure is cleaned up + var settingsPath = Path.Combine(workspace.WorkspaceRoot.FullName, ".aspire", "settings.json"); + var json = await File.ReadAllTextAsync(settingsPath); + var settings = JsonNode.Parse(json)?.AsObject(); + Assert.NotNull(settings); + Assert.False(settings.ContainsKey("features")); + } + + [Fact] + public async Task ConfigSetCommand_WithCorruptedFile_RecoversDuringLoad() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + + // Manually create a corrupted settings file with duplicate keys + // (flat colon key + nested object for the same path) + var settingsDir = Path.Combine(workspace.WorkspaceRoot.FullName, ".aspire"); + Directory.CreateDirectory(settingsDir); + var settingsPath = Path.Combine(settingsDir, "settings.json"); + await File.WriteAllTextAsync(settingsPath, """ + { + "features": { + "polyglotSupportEnabled": "false" + }, + "features:polyglotSupportEnabled": "true" + } + """); + + // Loading configuration should succeed after normalizing the corrupted file + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + // Verify the file was normalized - flat key should be gone, existing nested value preserved + var json = await File.ReadAllTextAsync(settingsPath); + var settings = JsonNode.Parse(json)?.AsObject(); + Assert.NotNull(settings); + Assert.False(settings.ContainsKey("features:polyglotSupportEnabled")); + Assert.True(settings["features"] is JsonObject); + var featuresObject = settings["features"]!.AsObject(); + Assert.Equal("false", featuresObject["polyglotSupportEnabled"]?.ToString()); + } + + [Fact] + public async Task ConfigSetCommand_WithCorruptedFile_PreservesExistingNestedValueOverFlatKey() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + + // Create a settings file where both a nested value and a flat colon key exist + // for the same path but with different values. + var settingsDir = Path.Combine(workspace.WorkspaceRoot.FullName, ".aspire"); + Directory.CreateDirectory(settingsDir); + var settingsPath = Path.Combine(settingsDir, "settings.json"); + await File.WriteAllTextAsync(settingsPath, """ + { + "features": { + "polyglotSupportEnabled": "nested-value" + }, + "features:polyglotSupportEnabled": "flat-value" + } + """); + + // Loading configuration triggers normalization + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + // The existing nested value should be preserved; the flat key value should be dropped + var json = await File.ReadAllTextAsync(settingsPath); + var settings = JsonNode.Parse(json)?.AsObject(); + Assert.NotNull(settings); + Assert.False(settings.ContainsKey("features:polyglotSupportEnabled")); + var featuresObject = settings["features"]!.AsObject(); + Assert.Equal("nested-value", featuresObject["polyglotSupportEnabled"]?.ToString()); + } } public class TestConfigurationService : IConfigurationService diff --git a/tests/Aspire.Cli.Tests/Commands/ResourceCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/ResourceCommandTests.cs index afde5158d15..7ad020f8ce5 100644 --- a/tests/Aspire.Cli.Tests/Commands/ResourceCommandTests.cs +++ b/tests/Aspire.Cli.Tests/Commands/ResourceCommandTests.cs @@ -18,7 +18,7 @@ public async Task ResourceCommand_Help_Works() var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService(); - var result = command.Parse("command --help"); + var result = command.Parse("resource --help"); var exitCode = await result.InvokeAsync().DefaultTimeout(); @@ -33,7 +33,7 @@ public async Task ResourceCommand_RequiresResourceArgument() var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService(); - var result = command.Parse("command"); + var result = command.Parse("resource"); // Missing required argument should fail var exitCode = await result.InvokeAsync().DefaultTimeout(); @@ -48,7 +48,7 @@ public async Task ResourceCommand_RequiresCommandArgument() var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService(); - var result = command.Parse("command myresource"); + var result = command.Parse("resource myresource"); // Missing required command argument should fail var exitCode = await result.InvokeAsync().DefaultTimeout(); @@ -63,7 +63,7 @@ public async Task ResourceCommand_AcceptsBothArguments() var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService(); - var result = command.Parse("command myresource my-command --help"); + var result = command.Parse("resource myresource my-command --help"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.Success, exitCode); @@ -77,14 +77,14 @@ public async Task ResourceCommand_AcceptsProjectOption() var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService(); - var result = command.Parse("command myresource my-command --apphost /path/to/project.csproj --help"); + var result = command.Parse("resource myresource my-command --apphost /path/to/project.csproj --help"); var exitCode = await result.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.Success, exitCode); } [Fact] - public async Task ResourceCommand_AcceptsKnownCommandNames() + public async Task ResourceCommand_AcceptsWellKnownCommandNames() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); @@ -92,19 +92,33 @@ public async Task ResourceCommand_AcceptsKnownCommandNames() var command = provider.GetRequiredService(); - // Test with resource-start - var startResult = command.Parse("command myresource resource-start --help"); + // Test with start + var startResult = command.Parse("resource myresource start --help"); var startExitCode = await startResult.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.Success, startExitCode); - // Test with resource-stop - var stopResult = command.Parse("command myresource resource-stop --help"); + // Test with stop + var stopResult = command.Parse("resource myresource stop --help"); var stopExitCode = await stopResult.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.Success, stopExitCode); - // Test with resource-restart - var restartResult = command.Parse("command myresource resource-restart --help"); + // Test with restart + var restartResult = command.Parse("resource myresource restart --help"); var restartExitCode = await restartResult.InvokeAsync().DefaultTimeout(); Assert.Equal(ExitCodeConstants.Success, restartExitCode); } + + [Fact] + public async Task ResourceCommand_AcceptsProjectOptionWithStart() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + var result = command.Parse("resource myresource start --apphost /path/to/project.csproj --help"); + + var exitCode = await result.InvokeAsync().DefaultTimeout(); + Assert.Equal(ExitCodeConstants.Success, exitCode); + } } diff --git a/tests/Aspire.Cli.Tests/Commands/RestartCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/RestartCommandTests.cs deleted file mode 100644 index 952ac8ef23d..00000000000 --- a/tests/Aspire.Cli.Tests/Commands/RestartCommandTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Aspire.Cli.Commands; -using Aspire.Cli.Tests.Utils; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.AspNetCore.InternalTesting; - -namespace Aspire.Cli.Tests.Commands; - -public class RestartCommandTests(ITestOutputHelper outputHelper) -{ - [Fact] - public async Task RestartCommand_Help_Works() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("restart --help"); - - var exitCode = await result.InvokeAsync().DefaultTimeout(); - - Assert.Equal(ExitCodeConstants.Success, exitCode); - } - - [Fact] - public async Task RestartCommand_RequiresResourceArgument() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("restart"); - - // Missing required argument should fail - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.NotEqual(ExitCodeConstants.Success, exitCode); - } - - [Fact] - public async Task RestartCommand_AcceptsResourceArgument() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("restart myresource --help"); - - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.Equal(ExitCodeConstants.Success, exitCode); - } - - [Fact] - public async Task RestartCommand_AcceptsProjectOption() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("restart myresource --apphost /path/to/project.csproj --help"); - - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.Equal(ExitCodeConstants.Success, exitCode); - } -} diff --git a/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs index f9c95c506be..56d1e6e6346 100644 --- a/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs +++ b/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs @@ -1479,6 +1479,21 @@ public async Task RunCommand_WithNoBuildAndWatchModeEnabled_ReturnsInvalidComman Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); } + [Fact] + public void RunCommand_ForwardsUnmatchedTokensToAppHost() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + var result = command.Parse("run -- --custom-arg value"); + + Assert.Empty(result.Errors); + Assert.Contains("--custom-arg", result.UnmatchedTokens); + Assert.Contains("value", result.UnmatchedTokens); + } + private sealed class TestFeatures : IFeatures { private readonly Dictionary _features = new(); diff --git a/tests/Aspire.Cli.Tests/Commands/StartCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/StartCommandTests.cs index e6a7146d81a..e1ed2ee9abe 100644 --- a/tests/Aspire.Cli.Tests/Commands/StartCommandTests.cs +++ b/tests/Aspire.Cli.Tests/Commands/StartCommandTests.cs @@ -25,49 +25,6 @@ public async Task StartCommand_Help_Works() Assert.Equal(ExitCodeConstants.Success, exitCode); } - [Fact] - public async Task StartCommand_RequiresResourceArgument() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("start"); - - // Missing required argument should fail - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.NotEqual(ExitCodeConstants.Success, exitCode); - } - - [Fact] - public async Task StartCommand_AcceptsResourceArgument() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("start myresource --help"); - - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.Equal(ExitCodeConstants.Success, exitCode); - } - - [Fact] - public async Task StartCommand_AcceptsProjectOption() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("start myresource --apphost /path/to/project.csproj --help"); - - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.Equal(ExitCodeConstants.Success, exitCode); - } - [Fact] public async Task StartCommand_AcceptsNoBuildOption() { @@ -111,30 +68,17 @@ public async Task StartCommand_AcceptsIsolatedOption() } [Fact] - public async Task StartCommand_FormatOptionNotValidWithResource() + public void StartCommand_ForwardsUnmatchedTokensToAppHost() { using var workspace = TemporaryWorkspace.Create(outputHelper); var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); var provider = services.BuildServiceProvider(); var command = provider.GetRequiredService(); - var result = command.Parse("start myresource --format json"); + var result = command.Parse("start -- --custom-arg value"); - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); - } - - [Fact] - public async Task StartCommand_IsolatedOptionNotValidWithResource() - { - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var command = provider.GetRequiredService(); - var result = command.Parse("start myresource --isolated"); - - var exitCode = await result.InvokeAsync().DefaultTimeout(); - Assert.Equal(ExitCodeConstants.InvalidCommand, exitCode); + Assert.Empty(result.Errors); + Assert.Contains("--custom-arg", result.UnmatchedTokens); + Assert.Contains("value", result.UnmatchedTokens); } } diff --git a/tests/Aspire.Cli.Tests/Commands/StopCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/StopCommandTests.cs new file mode 100644 index 00000000000..79e15c4ac71 --- /dev/null +++ b/tests/Aspire.Cli.Tests/Commands/StopCommandTests.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Cli.Commands; +using Aspire.Cli.Tests.Utils; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.InternalTesting; + +namespace Aspire.Cli.Tests.Commands; + +public class StopCommandTests(ITestOutputHelper outputHelper) +{ + [Fact] + public async Task StopCommand_Help_Works() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + var result = command.Parse("stop --help"); + + var exitCode = await result.InvokeAsync().DefaultTimeout(); + + Assert.Equal(ExitCodeConstants.Success, exitCode); + } + + [Fact] + public async Task StopCommand_RejectsPositionalResourceArgument() + { + using var workspace = TemporaryWorkspace.Create(outputHelper); + var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); + var provider = services.BuildServiceProvider(); + + var command = provider.GetRequiredService(); + var result = command.Parse("stop myresource"); + + var exitCode = await result.InvokeAsync().DefaultTimeout(); + Assert.NotEqual(ExitCodeConstants.Success, exitCode); + } +} diff --git a/tests/Aspire.Cli.Tests/Configuration/IntegrationReferenceTests.cs b/tests/Aspire.Cli.Tests/Configuration/IntegrationReferenceTests.cs new file mode 100644 index 00000000000..646321f32d6 --- /dev/null +++ b/tests/Aspire.Cli.Tests/Configuration/IntegrationReferenceTests.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Cli.Configuration; + +namespace Aspire.Cli.Tests.Configuration; + +public class IntegrationReferenceTests +{ + [Fact] + public void PackageReference_HasVersionAndNoProjectPath() + { + var reference = IntegrationReference.FromPackage("Aspire.Hosting.Redis", "13.2.0"); + + Assert.True(reference.IsPackageReference); + Assert.False(reference.IsProjectReference); + Assert.Equal("13.2.0", reference.Version); + Assert.Null(reference.ProjectPath); + } + + [Fact] + public void ProjectReference_HasProjectPathAndNoVersion() + { + var reference = IntegrationReference.FromProject("MyIntegration", "/path/to/MyIntegration.csproj"); + + Assert.True(reference.IsProjectReference); + Assert.False(reference.IsPackageReference); + Assert.Null(reference.Version); + Assert.Equal("/path/to/MyIntegration.csproj", reference.ProjectPath); + } + + [Fact] + public void GetIntegrationReferences_DetectsCsprojAsProjectReference() + { + var config = new AspireJsonConfiguration + { + SdkVersion = "13.2.0", + Packages = new Dictionary + { + ["Aspire.Hosting.Redis"] = "13.2.0", + ["MyIntegration"] = "../src/MyIntegration/MyIntegration.csproj" + } + }; + + var refs = config.GetIntegrationReferences("13.2.0", "/home/user/app").ToList(); + + // Base Aspire.Hosting + Redis (packages) + MyIntegration (project ref) = 3 + Assert.Equal(3, refs.Count); + + var packageRefs = refs.Where(r => r.IsPackageReference).ToList(); + var projectRefs = refs.Where(r => r.IsProjectReference).ToList(); + + Assert.Equal(2, packageRefs.Count); + Assert.Single(projectRefs); + Assert.Equal("MyIntegration", projectRefs[0].Name); + Assert.EndsWith(".csproj", projectRefs[0].ProjectPath!); + } + + [Fact] + public void GetIntegrationReferences_ResolvesRelativeProjectPath() + { + var config = new AspireJsonConfiguration + { + SdkVersion = "13.2.0", + Packages = new Dictionary + { + ["MyIntegration"] = "../MyIntegration/MyIntegration.csproj" + } + }; + + var refs = config.GetIntegrationReferences("13.2.0", "/home/user/app").ToList(); + var projectRef = refs.Single(r => r.IsProjectReference); + + // Path should be resolved to absolute + Assert.True(Path.IsPathRooted(projectRef.ProjectPath!)); + } + + [Fact] + public void GetIntegrationReferences_EmptyVersionDefaultsToSdkVersion() + { + var config = new AspireJsonConfiguration + { + SdkVersion = "13.2.0", + Packages = new Dictionary + { + ["Aspire.Hosting.Redis"] = "" + } + }; + + var refs = config.GetIntegrationReferences("13.2.0", "/tmp").ToList(); + var redis = refs.Single(r => r.Name == "Aspire.Hosting.Redis"); + + Assert.Equal("13.2.0", redis.Version); + Assert.True(redis.IsPackageReference); + } + + [Fact] + public void GetIntegrationReferences_SkipsBasePackages() + { + var config = new AspireJsonConfiguration + { + SdkVersion = "13.2.0", + Packages = new Dictionary + { + ["Aspire.Hosting"] = "13.2.0", + ["Aspire.Hosting.AppHost"] = "13.2.0", + ["Aspire.Hosting.Redis"] = "13.2.0" + } + }; + + var refs = config.GetIntegrationReferences("13.2.0", "/tmp").ToList(); + + // Base Aspire.Hosting (auto-added) + Redis = 2 + // Aspire.Hosting from packages dict is skipped (duplicate) + // Aspire.Hosting.AppHost is skipped (SDK-only) + Assert.Equal(2, refs.Count); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting"); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting.Redis"); + } +} diff --git a/tests/Aspire.Cli.Tests/Mcp/ExecuteResourceCommandToolTests.cs b/tests/Aspire.Cli.Tests/Mcp/ExecuteResourceCommandToolTests.cs index 8e923c714ba..492dab151bc 100644 --- a/tests/Aspire.Cli.Tests/Mcp/ExecuteResourceCommandToolTests.cs +++ b/tests/Aspire.Cli.Tests/Mcp/ExecuteResourceCommandToolTests.cs @@ -31,7 +31,7 @@ public async Task ExecuteResourceCommandTool_ThrowsException_WhenNoAppHostRunnin var tool = new ExecuteResourceCommandTool(monitor, NullLogger.Instance); var exception = await Assert.ThrowsAsync( - () => tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("test-resource", "resource-start")), CancellationToken.None).AsTask()).DefaultTimeout(); + () => tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("test-resource", "start")), CancellationToken.None).AsTask()).DefaultTimeout(); Assert.Contains("No Aspire AppHost", exception.Message); Assert.Contains("--detach", exception.Message); @@ -48,7 +48,7 @@ public async Task ExecuteResourceCommandTool_ReturnsSuccess_WhenCommandExecutedS monitor.AddConnection("hash1", "socket.hash1", connection); var tool = new ExecuteResourceCommandTool(monitor, NullLogger.Instance); - var result = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "resource-start")), CancellationToken.None).DefaultTimeout(); + var result = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "start")), CancellationToken.None).DefaultTimeout(); Assert.True(result.IsError is null or false); Assert.NotNull(result.Content); @@ -57,7 +57,7 @@ public async Task ExecuteResourceCommandTool_ReturnsSuccess_WhenCommandExecutedS Assert.NotNull(textContent); Assert.Contains("successfully", textContent.Text); Assert.Contains("api-service", textContent.Text); - Assert.Contains("resource-start", textContent.Text); + Assert.Contains("start", textContent.Text); } [Fact] @@ -77,7 +77,7 @@ public async Task ExecuteResourceCommandTool_ThrowsException_WhenCommandFails() var tool = new ExecuteResourceCommandTool(monitor, NullLogger.Instance); var exception = await Assert.ThrowsAsync( - () => tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("nonexistent", "resource-start")), CancellationToken.None).AsTask()).DefaultTimeout(); + () => tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("nonexistent", "start")), CancellationToken.None).AsTask()).DefaultTimeout(); Assert.Contains("Resource not found", exception.Message); } @@ -99,7 +99,7 @@ public async Task ExecuteResourceCommandTool_ThrowsException_WhenCommandCanceled var tool = new ExecuteResourceCommandTool(monitor, NullLogger.Instance); var exception = await Assert.ThrowsAsync( - () => tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "resource-stop")), CancellationToken.None).AsTask()).DefaultTimeout(); + () => tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "stop")), CancellationToken.None).AsTask()).DefaultTimeout(); Assert.Contains("cancelled", exception.Message); } @@ -116,16 +116,16 @@ public async Task ExecuteResourceCommandTool_WorksWithKnownCommands() var tool = new ExecuteResourceCommandTool(monitor, NullLogger.Instance); - // Test with resource-start - var startResult = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "resource-start")), CancellationToken.None).DefaultTimeout(); + // Test with start + var startResult = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "start")), CancellationToken.None).DefaultTimeout(); Assert.True(startResult.IsError is null or false); - // Test with resource-stop - var stopResult = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "resource-stop")), CancellationToken.None).DefaultTimeout(); + // Test with stop + var stopResult = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "stop")), CancellationToken.None).DefaultTimeout(); Assert.True(stopResult.IsError is null or false); - // Test with resource-restart - var restartResult = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "resource-restart")), CancellationToken.None).DefaultTimeout(); + // Test with restart + var restartResult = await tool.CallToolAsync(CallToolContextTestHelper.Create(CreateArguments("api-service", "restart")), CancellationToken.None).DefaultTimeout(); Assert.True(restartResult.IsError is null or false); } diff --git a/tests/Aspire.Cli.Tests/Projects/AppHostServerProjectTests.cs b/tests/Aspire.Cli.Tests/Projects/AppHostServerProjectTests.cs index 7ebdea5e7fd..85a7a59d689 100644 --- a/tests/Aspire.Cli.Tests/Projects/AppHostServerProjectTests.cs +++ b/tests/Aspire.Cli.Tests/Projects/AppHostServerProjectTests.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.InternalTesting; using System.Xml.Linq; +using Aspire.Cli.Configuration; using Aspire.Cli.NuGet; using Aspire.Cli.Packaging; using Aspire.Cli.Projects; @@ -47,12 +48,12 @@ public async Task CreateProjectFiles_AppSettingsJson_MatchesSnapshot() { // Arrange var project = CreateProject(); - var packages = new List<(string Name, string Version)> + var packages = new List { - ("Aspire.Hosting", "13.1.0"), - ("Aspire.Hosting.Redis", "13.1.0"), - ("Aspire.Hosting.PostgreSQL", "13.1.0"), - ("Aspire.Hosting.CodeGeneration.TypeScript", "13.1.0") + IntegrationReference.FromPackage("Aspire.Hosting", "13.1.0"), + IntegrationReference.FromPackage("Aspire.Hosting.Redis", "13.1.0"), + IntegrationReference.FromPackage("Aspire.Hosting.PostgreSQL", "13.1.0"), + IntegrationReference.FromPackage("Aspire.Hosting.CodeGeneration.TypeScript", "13.1.0") }; // Act @@ -71,9 +72,9 @@ public async Task CreateProjectFiles_ProgramCs_MatchesSnapshot() { // Arrange var project = CreateProject(); - var packages = new List<(string Name, string Version)> + var packages = new List { - ("Aspire.Hosting", "13.1.0") + IntegrationReference.FromPackage("Aspire.Hosting", "13.1.0") }; // Act @@ -93,9 +94,9 @@ public async Task CreateProjectFiles_GeneratesProgramCs() { // Arrange var project = CreateProject(); - var packages = new List<(string Name, string Version)> + var packages = new List { - ("Aspire.Hosting", "13.1.0") + IntegrationReference.FromPackage("Aspire.Hosting", "13.1.0") }; // Act @@ -114,11 +115,11 @@ public async Task CreateProjectFiles_GeneratesAppSettingsJson_WithAtsAssemblies( { // Arrange var project = CreateProject(); - var packages = new List<(string Name, string Version)> + var packages = new List { - ("Aspire.Hosting", "13.1.0"), - ("Aspire.Hosting.Redis", "13.1.0"), - ("Aspire.Hosting.CodeGeneration.TypeScript", "13.1.0") + IntegrationReference.FromPackage("Aspire.Hosting", "13.1.0"), + IntegrationReference.FromPackage("Aspire.Hosting.Redis", "13.1.0"), + IntegrationReference.FromPackage("Aspire.Hosting.CodeGeneration.TypeScript", "13.1.0") }; // Act @@ -140,9 +141,9 @@ public async Task CreateProjectFiles_CopiesAppSettingsToOutput() { // Arrange var project = CreateProject(); - var packages = new List<(string Name, string Version)> + var packages = new List { - ("Aspire.Hosting", "13.1.0") + IntegrationReference.FromPackage("Aspire.Hosting", "13.1.0") }; // Act @@ -260,11 +261,11 @@ await File.WriteAllTextAsync(settingsJson, """ var projectModelPath = Path.Combine(appPath, ".aspire_server"); var project = new DotNetBasedAppHostServerProject(appPath, "test.sock", appPath, runner, packagingService, configurationService, logger, projectModelPath); - var packages = new List<(string Name, string Version)> + var packages = new List { - ("Aspire.Hosting", "13.1.0"), - ("Aspire.Hosting.AppHost", "13.1.0"), - ("Aspire.Hosting.Redis", "13.1.0") + IntegrationReference.FromPackage("Aspire.Hosting", "13.1.0"), + IntegrationReference.FromPackage("Aspire.Hosting.AppHost", "13.1.0"), + IntegrationReference.FromPackage("Aspire.Hosting.Redis", "13.1.0") }; // Act @@ -287,48 +288,19 @@ await File.WriteAllTextAsync(settingsJson, """ } outputHelper.WriteLine("================================"); - // Assert - verify nuget.config uses the correct channel - // Note: NuGetConfigMerger creates the file as "nuget.config" (lowercase) - var nugetConfigPath = Path.Combine(project.ProjectModelPath, "nuget.config"); - - // Build diagnostic info for assertion failure - var diagnosticInfo = new System.Text.StringBuilder(); - diagnosticInfo.AppendLine($"appPath: {appPath}"); - diagnosticInfo.AppendLine($"settingsJson path: {settingsJson}"); - diagnosticInfo.AppendLine($"settingsJson exists: {File.Exists(settingsJson)}"); - if (File.Exists(settingsJson)) - { - diagnosticInfo.AppendLine($"settingsJson content: {File.ReadAllText(settingsJson)}"); - } - diagnosticInfo.AppendLine($"project.ProjectModelPath: {project.ProjectModelPath}"); - diagnosticInfo.AppendLine($"nugetConfigPath: {nugetConfigPath}"); - diagnosticInfo.AppendLine($"nugetConfigPath exists: {File.Exists(nugetConfigPath)}"); - - // List all files for debugging case sensitivity issues - if (Directory.Exists(project.ProjectModelPath)) - { - diagnosticInfo.AppendLine("Files in ProjectModelPath:"); - foreach (var file in Directory.GetFiles(project.ProjectModelPath)) - { - diagnosticInfo.AppendLine($" - {Path.GetFileName(file)}"); - } - } - - // The nuget.config should exist - Assert.True(File.Exists(nugetConfigPath), $"nuget.config should be created\n\nDiagnostics:\n{diagnosticInfo}"); - - var nugetConfigContent = await File.ReadAllTextAsync(nugetConfigPath); - - // Normalize paths for snapshot (replace machine-specific paths) - var normalizedContent = nugetConfigContent - .Replace(prNewHive.FullName, "{PR_NEW_HIVE}") - .Replace(prOldHive.FullName, "{PR_OLD_HIVE}"); - - // Snapshot verification - this will fail if the bug exists - // Expected: Contains {PR_NEW_HIVE} (project-local channel) - // Bug behavior: Contains {PR_OLD_HIVE} (global config channel) - await Verify(normalizedContent, extension: "xml") - .UseFileName("AppHostServerProject_NuGetConfig_UsesProjectLocalChannel"); + // Assert - verify the csproj uses RestoreAdditionalProjectSources with the correct channel sources + var projectFilePath = Path.Combine(project.ProjectModelPath, DotNetBasedAppHostServerProject.ProjectFileName); + + Assert.True(File.Exists(projectFilePath), $"Project file should be created at {projectFilePath}"); + + var projectContent = await File.ReadAllTextAsync(projectFilePath); + var projectDoc = XDocument.Parse(projectContent); + var restoreSources = projectDoc.Descendants("RestoreAdditionalProjectSources").FirstOrDefault()?.Value; + + // Should contain the pr-new hive path (project-local channel), NOT pr-old (global config) + Assert.NotNull(restoreSources); + Assert.Contains(prNewHive.FullName, restoreSources); + Assert.DoesNotContain(prOldHive.FullName, restoreSources); } /// diff --git a/tests/Aspire.Cli.Tests/Projects/GuestAppHostProjectTests.cs b/tests/Aspire.Cli.Tests/Projects/GuestAppHostProjectTests.cs index 876be8d1451..aa0b030d4cf 100644 --- a/tests/Aspire.Cli.Tests/Projects/GuestAppHostProjectTests.cs +++ b/tests/Aspire.Cli.Tests/Projects/GuestAppHostProjectTests.cs @@ -123,7 +123,7 @@ public void AspireJsonConfiguration_AddOrUpdatePackage_UpdatesExistingPackage() } [Fact] - public void AspireJsonConfiguration_GetAllPackages_IncludesBasePackages() + public void AspireJsonConfiguration_GetIntegrationReferences_IncludesBasePackages() { // Arrange var config = new AspireJsonConfiguration @@ -137,17 +137,16 @@ public void AspireJsonConfiguration_GetAllPackages_IncludesBasePackages() }; // Act - var packages = config.GetAllPackages().ToList(); + var refs = config.GetIntegrationReferences("13.1.0", "/tmp").ToList(); // Assert - should include base package (Aspire.Hosting) plus explicit packages - // Note: Aspire.Hosting.AppHost is an SDK-only package and is excluded - Assert.Contains(packages, p => p.Name == "Aspire.Hosting" && p.Version == "13.1.0"); - Assert.Contains(packages, p => p.Name == "Aspire.Hosting.Redis" && p.Version == "13.1.0"); - Assert.Equal(2, packages.Count); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting" && r.Version == "13.1.0" && !r.IsProjectReference); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting.Redis" && r.Version == "13.1.0" && !r.IsProjectReference); + Assert.Equal(2, refs.Count); } [Fact] - public void AspireJsonConfiguration_GetAllPackages_WithNoExplicitPackages_ReturnsBasePackagesOnly() + public void AspireJsonConfiguration_GetIntegrationReferences_WithNoExplicitPackages_ReturnsBasePackagesOnly() { // Arrange var config = new AspireJsonConfiguration @@ -157,70 +156,83 @@ public void AspireJsonConfiguration_GetAllPackages_WithNoExplicitPackages_Return }; // Act - var packages = config.GetAllPackages().ToList(); + var refs = config.GetIntegrationReferences("13.1.0", "/tmp").ToList(); // Assert - should include base package only (Aspire.Hosting) - // Note: Aspire.Hosting.AppHost is an SDK-only package and is excluded - Assert.Single(packages); - Assert.Contains(packages, p => p.Name == "Aspire.Hosting" && p.Version == "13.1.0"); + Assert.Single(refs); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting" && r.Version == "13.1.0"); } [Fact] - public void AspireJsonConfiguration_GetAllPackages_WithWhitespaceSdkVersion_Throws() + public void AspireJsonConfiguration_GetIntegrationReferences_WithEmptyVersion_UsesFallbackVersion() { + // Arrange var config = new AspireJsonConfiguration { - SdkVersion = " ", - Language = "typescript" + Language = "typescript", + Packages = new Dictionary + { + ["Aspire.Hosting.Redis"] = string.Empty + } }; - var exception = Assert.Throws(() => config.GetAllPackages().ToList()); + // Act + var refs = config.GetIntegrationReferences("13.1.0", "/tmp").ToList(); - Assert.Contains("non-empty", exception.Message); + // Assert + Assert.Contains(refs, r => r.Name == "Aspire.Hosting" && r.Version == "13.1.0"); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting.Redis" && r.Version == "13.1.0"); } [Fact] - public void AspireJsonConfiguration_GetAllPackages_WithDefaultSdkVersion_UsesFallbackVersion() + public void AspireJsonConfiguration_GetIntegrationReferences_WithConfiguredSdkVersion_ReturnsConfiguredVersions() { // Arrange var config = new AspireJsonConfiguration { + SdkVersion = "13.1.0", Language = "typescript", + Channel = "daily", Packages = new Dictionary { - ["Aspire.Hosting.Redis"] = string.Empty + ["Aspire.Hosting.Redis"] = "13.1.0" } }; // Act - var packages = config.GetAllPackages("13.1.0").ToList(); + var refs = config.GetIntegrationReferences("13.1.0", "/tmp").ToList(); // Assert - Assert.Contains(packages, p => p.Name == "Aspire.Hosting" && p.Version == "13.1.0"); - Assert.Contains(packages, p => p.Name == "Aspire.Hosting.Redis" && p.Version == "13.1.0"); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting" && r.Version == "13.1.0"); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting.Redis" && r.Version == "13.1.0"); } [Fact] - public void AspireJsonConfiguration_GetAllPackages_WithConfiguredSdkVersion_ReturnsConfiguredVersions() + public void AspireJsonConfiguration_GetIntegrationReferences_WithProjectReference_ReturnsProjectRef() { // Arrange var config = new AspireJsonConfiguration { SdkVersion = "13.1.0", Language = "typescript", - Channel = "daily", Packages = new Dictionary { - ["Aspire.Hosting.Redis"] = "13.1.0" + ["Aspire.Hosting.Redis"] = "13.1.0", + ["Aspire.Hosting.MyCustom"] = "../src/Aspire.Hosting.MyCustom/Aspire.Hosting.MyCustom.csproj" } }; // Act - var packages = config.GetAllPackages("13.1.0").ToList(); + var refs = config.GetIntegrationReferences("13.1.0", "/home/user/app").ToList(); // Assert - Assert.Contains(packages, p => p.Name == "Aspire.Hosting" && p.Version == "13.1.0"); - Assert.Contains(packages, p => p.Name == "Aspire.Hosting.Redis" && p.Version == "13.1.0"); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting" && r.IsPackageReference); + Assert.Contains(refs, r => r.Name == "Aspire.Hosting.Redis" && r.IsPackageReference); + var projectRef = Assert.Single(refs, r => r.IsProjectReference); + Assert.Equal("Aspire.Hosting.MyCustom", projectRef.Name); + Assert.Null(projectRef.Version); + Assert.NotNull(projectRef.ProjectPath); + Assert.EndsWith(".csproj", projectRef.ProjectPath); } [Fact] diff --git a/tests/Aspire.Cli.Tests/Projects/PrebuiltAppHostServerTests.cs b/tests/Aspire.Cli.Tests/Projects/PrebuiltAppHostServerTests.cs new file mode 100644 index 00000000000..b172eba4a5c --- /dev/null +++ b/tests/Aspire.Cli.Tests/Projects/PrebuiltAppHostServerTests.cs @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Xml.Linq; +using Aspire.Cli.Configuration; +using Aspire.Cli.Projects; + +namespace Aspire.Cli.Tests.Projects; + +public class PrebuiltAppHostServerTests +{ + [Fact] + public void GenerateIntegrationProjectFile_WithPackagesOnly_ProducesPackageReferences() + { + var packageRefs = new List + { + IntegrationReference.FromPackage("Aspire.Hosting", "13.2.0"), + IntegrationReference.FromPackage("Aspire.Hosting.Redis", "13.2.0") + }; + var projectRefs = new List(); + + var xml = PrebuiltAppHostServer.GenerateIntegrationProjectFile(packageRefs, projectRefs, "/tmp/libs"); + var doc = XDocument.Parse(xml); + + var packageElements = doc.Descendants("PackageReference").ToList(); + Assert.Equal(2, packageElements.Count); + Assert.Contains(packageElements, e => e.Attribute("Include")?.Value == "Aspire.Hosting" && e.Attribute("Version")?.Value == "13.2.0"); + Assert.Contains(packageElements, e => e.Attribute("Include")?.Value == "Aspire.Hosting.Redis" && e.Attribute("Version")?.Value == "13.2.0"); + + Assert.Empty(doc.Descendants("ProjectReference")); + } + + [Fact] + public void GenerateIntegrationProjectFile_WithProjectRefsOnly_ProducesProjectReferences() + { + var packageRefs = new List(); + var projectRefs = new List + { + IntegrationReference.FromProject("MyIntegration", "/path/to/MyIntegration.csproj") + }; + + var xml = PrebuiltAppHostServer.GenerateIntegrationProjectFile(packageRefs, projectRefs, "/tmp/libs"); + var doc = XDocument.Parse(xml); + + var projectElements = doc.Descendants("ProjectReference").ToList(); + Assert.Single(projectElements); + Assert.Equal("/path/to/MyIntegration.csproj", projectElements[0].Attribute("Include")?.Value); + + Assert.Empty(doc.Descendants("PackageReference")); + } + + [Fact] + public void GenerateIntegrationProjectFile_WithMixed_ProducesBothReferenceTypes() + { + var packageRefs = new List + { + IntegrationReference.FromPackage("Aspire.Hosting", "13.2.0"), + IntegrationReference.FromPackage("Aspire.Hosting.Redis", "13.2.0") + }; + var projectRefs = new List + { + IntegrationReference.FromProject("MyIntegration", "/path/to/MyIntegration.csproj") + }; + + var xml = PrebuiltAppHostServer.GenerateIntegrationProjectFile(packageRefs, projectRefs, "/tmp/libs"); + var doc = XDocument.Parse(xml); + + Assert.Equal(2, doc.Descendants("PackageReference").Count()); + Assert.Single(doc.Descendants("ProjectReference")); + } + + [Fact] + public void GenerateIntegrationProjectFile_SetsOutDir() + { + var packageRefs = new List + { + IntegrationReference.FromPackage("Aspire.Hosting", "13.2.0") + }; + var projectRefs = new List(); + + var xml = PrebuiltAppHostServer.GenerateIntegrationProjectFile(packageRefs, projectRefs, "/custom/output/path"); + var doc = XDocument.Parse(xml); + + var ns = doc.Root!.GetDefaultNamespace(); + var outDir = doc.Descendants(ns + "OutDir").FirstOrDefault()?.Value; + Assert.Equal("/custom/output/path", outDir); + } + + [Fact] + public void GenerateIntegrationProjectFile_HasCopyLocalLockFileAssemblies() + { + var xml = PrebuiltAppHostServer.GenerateIntegrationProjectFile([], [], "/tmp/libs"); + var doc = XDocument.Parse(xml); + + var ns = doc.Root!.GetDefaultNamespace(); + var copyLocal = doc.Descendants(ns + "CopyLocalLockFileAssemblies").FirstOrDefault()?.Value; + Assert.Equal("true", copyLocal); + } + + [Fact] + public void GenerateIntegrationProjectFile_DisablesAnalyzersAndDocGen() + { + var xml = PrebuiltAppHostServer.GenerateIntegrationProjectFile([], [], "/tmp/libs"); + var doc = XDocument.Parse(xml); + + var ns = doc.Root!.GetDefaultNamespace(); + Assert.Equal("false", doc.Descendants(ns + "EnableNETAnalyzers").FirstOrDefault()?.Value); + Assert.Equal("false", doc.Descendants(ns + "GenerateDocumentationFile").FirstOrDefault()?.Value); + Assert.Equal("false", doc.Descendants(ns + "ProduceReferenceAssembly").FirstOrDefault()?.Value); + } + + [Fact] + public void GenerateIntegrationProjectFile_TargetsNet10() + { + var xml = PrebuiltAppHostServer.GenerateIntegrationProjectFile([], [], "/tmp/libs"); + var doc = XDocument.Parse(xml); + + var ns = doc.Root!.GetDefaultNamespace(); + Assert.Equal("net10.0", doc.Descendants(ns + "TargetFramework").FirstOrDefault()?.Value); + } +} diff --git a/tests/Aspire.Cli.Tests/Snapshots/AppHostServerProject_NuGetConfig_UsesProjectLocalChannel.verified.xml b/tests/Aspire.Cli.Tests/Snapshots/AppHostServerProject_NuGetConfig_UsesProjectLocalChannel.verified.xml deleted file mode 100644 index beb326e5ea6..00000000000 --- a/tests/Aspire.Cli.Tests/Snapshots/AppHostServerProject_NuGetConfig_UsesProjectLocalChannel.verified.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/Aspire.Cli.Tests/Telemetry/AspireCliTelemetryTests.cs b/tests/Aspire.Cli.Tests/Telemetry/AspireCliTelemetryTests.cs index d5c6f317517..9d273642a25 100644 --- a/tests/Aspire.Cli.Tests/Telemetry/AspireCliTelemetryTests.cs +++ b/tests/Aspire.Cli.Tests/Telemetry/AspireCliTelemetryTests.cs @@ -198,6 +198,20 @@ public void InitializeAsync_AddsMachineInformationTags() Assert.Contains(tags, t => t.Key == "machine.mac_address_hash" && (string?)t.Value == "test-mac-hash"); } + [Fact] + public void InitializeAsync_AddsOsInformationTags() + { + using var fixture = new TelemetryFixture(); + + var tags = fixture.Telemetry.GetDefaultTags(); + + var expectedOsName = AspireCliTelemetry.GetOsName(); + var expectedOsType = AspireCliTelemetry.GetOsType(); + Assert.Contains(tags, t => t.Key == TelemetryConstants.Tags.OsName && (string?)t.Value == expectedOsName); + Assert.Contains(tags, t => t.Key == TelemetryConstants.Tags.OsVersion && t.Value is string s && s == Environment.OSVersion.Version.ToString()); + Assert.Contains(tags, t => t.Key == TelemetryConstants.Tags.OsType && (string?)t.Value == expectedOsType); + } + [Fact] public void StartReportedActivity_IncludesAllDefaultTags() { diff --git a/tests/Aspire.Cli.Tests/TestServices/TestAppHostServerSessionFactory.cs b/tests/Aspire.Cli.Tests/TestServices/TestAppHostServerSessionFactory.cs index 1a5451fda59..fcaa77b92ef 100644 --- a/tests/Aspire.Cli.Tests/TestServices/TestAppHostServerSessionFactory.cs +++ b/tests/Aspire.Cli.Tests/TestServices/TestAppHostServerSessionFactory.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Aspire.Cli.Configuration; using Aspire.Cli.Projects; using Aspire.Cli.Utils; @@ -14,7 +15,7 @@ internal sealed class TestAppHostServerSessionFactory : IAppHostServerSessionFac public Task CreateAsync( string appHostPath, string sdkVersion, - IEnumerable<(string PackageId, string Version)> packages, + IEnumerable integrations, Dictionary? launchSettingsEnvVars, bool debug, CancellationToken cancellationToken) diff --git a/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs b/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs index 32ef1a8de78..2546f6bd1ba 100644 --- a/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs +++ b/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs @@ -169,7 +169,6 @@ public static IServiceCollection CreateServiceCollection(TemporaryWorkspace work services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/tests/Aspire.Dashboard.Tests/Integration/McpServiceTests.cs b/tests/Aspire.Dashboard.Tests/Integration/McpServiceTests.cs index 16a9a0b7e65..04bff74f41e 100644 --- a/tests/Aspire.Dashboard.Tests/Integration/McpServiceTests.cs +++ b/tests/Aspire.Dashboard.Tests/Integration/McpServiceTests.cs @@ -32,7 +32,8 @@ public async Task CallService_McpEndPoint_Success() using var httpClient = IntegrationTestHelpers.CreateHttpClient($"http://{app.McpEndPointAccessor().EndPoint}"); - var request = CreateListToolsRequest(); + var sessionId = await InitializeSessionAsync(httpClient); + var request = CreateListToolsRequest(sessionId); // Act var responseMessage = await httpClient.SendAsync(request).DefaultTimeout(TestConstants.LongTimeoutDuration); @@ -105,11 +106,14 @@ public async Task CallService_McpEndPoint_RequiredApiKeySent_Success() using var httpClient = IntegrationTestHelpers.CreateHttpClient($"http://{app.McpEndPointAccessor().EndPoint}"); - var requestMessage = CreateListToolsRequest(); - requestMessage.Headers.TryAddWithoutValidation(McpApiKeyAuthenticationHandler.McpApiKeyHeaderName, apiKey); + void AddApiKey(HttpRequestMessage r) => r.Headers.TryAddWithoutValidation(McpApiKeyAuthenticationHandler.McpApiKeyHeaderName, apiKey); - // Act - var responseMessage = await httpClient.SendAsync(requestMessage).DefaultTimeout(TestConstants.LongTimeoutDuration); + var sessionId = await InitializeSessionAsync(httpClient, AddApiKey); + + var listRequest = CreateListToolsRequest(sessionId); + AddApiKey(listRequest); + + var responseMessage = await httpClient.SendAsync(listRequest).DefaultTimeout(TestConstants.LongTimeoutDuration); responseMessage.EnsureSuccessStatusCode(); var responseData = await GetDataFromSseResponseAsync(responseMessage); @@ -130,7 +134,8 @@ public async Task CallService_NoResourceService_ResourceToolsNotRegistered() using var httpClient = IntegrationTestHelpers.CreateHttpClient($"http://{app.McpEndPointAccessor().EndPoint}"); - var request = CreateListToolsRequest(); + var sessionId = await InitializeSessionAsync(httpClient); + var request = CreateListToolsRequest(sessionId); // Act var responseMessage = await httpClient.SendAsync(request).DefaultTimeout(TestConstants.LongTimeoutDuration); @@ -166,7 +171,8 @@ public async Task CallService_WithResourceService_ResourceToolsRegistered() using var httpClient = IntegrationTestHelpers.CreateHttpClient($"http://{app.McpEndPointAccessor().EndPoint}"); - var request = CreateListToolsRequest(); + var sessionId = await InitializeSessionAsync(httpClient); + var request = CreateListToolsRequest(sessionId); // Act var responseMessage = await httpClient.SendAsync(request).DefaultTimeout(TestConstants.LongTimeoutDuration); @@ -226,7 +232,8 @@ public async Task CallService_McpEndPointHttpOnly_Success() using var httpClient = IntegrationTestHelpers.CreateHttpClient($"http://{app.McpEndPointAccessor().EndPoint}"); - var request = CreateListToolsRequest(); + var sessionId = await InitializeSessionAsync(httpClient); + var request = CreateListToolsRequest(sessionId); // Act var responseMessage = await httpClient.SendAsync(request).DefaultTimeout(TestConstants.LongTimeoutDuration); @@ -263,7 +270,8 @@ public async Task CallService_McpTool_TelemetryRecorded() using var httpClient = IntegrationTestHelpers.CreateHttpClient($"http://{app.McpEndPointAccessor().EndPoint}"); - var request = CreateListToolsRequest(); + var sessionId = await InitializeSessionAsync(httpClient); + var request = CreateListToolsRequest(sessionId); // Act var responseMessage = await httpClient.SendAsync(request).DefaultTimeout(TestConstants.LongTimeoutDuration); @@ -297,7 +305,75 @@ public async Task CallService_McpTool_TelemetryRecorded() Assert.True(foundEndOperation, "Expected to find EndOperation telemetry event"); } - internal static HttpRequestMessage CreateListToolsRequest() + internal static HttpRequestMessage CreateInitializeRequest(string? sessionId = null) + { + var json = + """ + { + "jsonrpc": "2.0", + "id": "init", + "method": "initialize", + "params": { + "protocolVersion": "2025-03-26", + "capabilities": {}, + "clientInfo": { + "name": "test-client", + "version": "1.0.0" + } + } + } + """; + var content = new ByteArrayContent(Encoding.UTF8.GetBytes(json)); + content.Headers.TryAddWithoutValidation("content-type", "application/json"); + var request = new HttpRequestMessage(HttpMethod.Post, "/mcp") + { + Content = content + }; + request.Headers.TryAddWithoutValidation("accept", "application/json"); + request.Headers.TryAddWithoutValidation("accept", "text/event-stream"); + if (sessionId is not null) + { + request.Headers.TryAddWithoutValidation("Mcp-Session-Id", sessionId); + } + return request; + } + + internal static async Task InitializeSessionAsync(HttpClient httpClient, Action? configureRequest = null) + { + var initRequest = CreateInitializeRequest(); + configureRequest?.Invoke(initRequest); + var initResponse = await httpClient.SendAsync(initRequest).DefaultTimeout(TestConstants.LongTimeoutDuration); + initResponse.EnsureSuccessStatusCode(); + var sessionId = initResponse.Headers.GetValues("Mcp-Session-Id").First(); + + // Consume the SSE response body to properly release the connection + await initResponse.Content.ReadAsStringAsync().DefaultTimeout(TestConstants.LongTimeoutDuration); + + // Send initialized notification + var notificationJson = + """ + { + "jsonrpc": "2.0", + "method": "notifications/initialized" + } + """; + var notificationContent = new ByteArrayContent(Encoding.UTF8.GetBytes(notificationJson)); + notificationContent.Headers.TryAddWithoutValidation("content-type", "application/json"); + var notificationRequest = new HttpRequestMessage(HttpMethod.Post, "/mcp") + { + Content = notificationContent + }; + notificationRequest.Headers.TryAddWithoutValidation("accept", "application/json"); + notificationRequest.Headers.TryAddWithoutValidation("accept", "text/event-stream"); + notificationRequest.Headers.TryAddWithoutValidation("Mcp-Session-Id", sessionId); + configureRequest?.Invoke(notificationRequest); + var notificationResponse = await httpClient.SendAsync(notificationRequest).DefaultTimeout(TestConstants.LongTimeoutDuration); + notificationResponse.EnsureSuccessStatusCode(); + + return sessionId; + } + + internal static HttpRequestMessage CreateListToolsRequest(string? sessionId = null) { var json = """ @@ -316,6 +392,10 @@ internal static HttpRequestMessage CreateListToolsRequest() }; request.Headers.TryAddWithoutValidation("accept", "application/json"); request.Headers.TryAddWithoutValidation("accept", "text/event-stream"); + if (sessionId is not null) + { + request.Headers.TryAddWithoutValidation("Mcp-Session-Id", sessionId); + } return request; } diff --git a/tests/Aspire.Dashboard.Tests/Integration/StartupTests.cs b/tests/Aspire.Dashboard.Tests/Integration/StartupTests.cs index 51ac994d4af..c0473235abe 100644 --- a/tests/Aspire.Dashboard.Tests/Integration/StartupTests.cs +++ b/tests/Aspire.Dashboard.Tests/Integration/StartupTests.cs @@ -416,7 +416,8 @@ await ServerRetryHelper.BindPortWithRetry(async port => { BaseAddress = new Uri($"https://{app.McpEndPointAccessor().EndPoint}") }; - var mcpRequest = McpServiceTests.CreateListToolsRequest(); + var mcpSessionId = await McpServiceTests.InitializeSessionAsync(mcpHttpClient); + var mcpRequest = McpServiceTests.CreateListToolsRequest(mcpSessionId); var responseMessage = await mcpHttpClient.SendAsync(mcpRequest).DefaultTimeout(TestConstants.LongTimeoutDuration); responseMessage.EnsureSuccessStatusCode(); diff --git a/tests/Aspire.Hosting.RemoteHost.Tests/AtsMarshallerTests.cs b/tests/Aspire.Hosting.RemoteHost.Tests/AtsMarshallerTests.cs index ff8756b73f8..1b4865ac792 100644 --- a/tests/Aspire.Hosting.RemoteHost.Tests/AtsMarshallerTests.cs +++ b/tests/Aspire.Hosting.RemoteHost.Tests/AtsMarshallerTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using Aspire.Hosting.Ats; using Aspire.Hosting.RemoteHost.Ats; using Xunit; @@ -18,7 +19,14 @@ private static AtsContext CreateTestContext() HandleTypes = [], DtoTypes = [ new AtsDtoTypeInfo { TypeId = "test/TestDto", Name = "TestDto", ClrType = typeof(TestDto), Properties = [] }, - new AtsDtoTypeInfo { TypeId = "test/TestDtoWithEnum", Name = "TestDtoWithEnum", ClrType = typeof(TestDtoWithEnum), Properties = [] } + new AtsDtoTypeInfo { TypeId = "test/TestDtoWithEnum", Name = "TestDtoWithEnum", ClrType = typeof(TestDtoWithEnum), Properties = [] }, + new AtsDtoTypeInfo { TypeId = "test/TestDto", Name = "TestDto", ClrType = typeof(TestDto), Properties = [] }, + new AtsDtoTypeInfo { TypeId = "test/SelfReferencingDto", Name = "SelfReferencingDto", ClrType = typeof(SelfReferencingDto), Properties = [] }, + new AtsDtoTypeInfo { TypeId = "test/ParentDto", Name = "ParentDto", ClrType = typeof(ParentDto), Properties = [] }, + new AtsDtoTypeInfo { TypeId = "test/ChildDto", Name = "ChildDto", ClrType = typeof(ChildDto), Properties = [] }, + new AtsDtoTypeInfo { TypeId = "test/DtoWithJsonPropertyName", Name = "DtoWithJsonPropertyName", ClrType = typeof(DtoWithJsonPropertyName), Properties = [] }, + new AtsDtoTypeInfo { TypeId = "test/DtoWithJsonIgnore", Name = "DtoWithJsonIgnore", ClrType = typeof(DtoWithJsonIgnore), Properties = [] }, + new AtsDtoTypeInfo { TypeId = "test/DtoWithReadOnlyProperty", Name = "DtoWithReadOnlyProperty", ClrType = typeof(DtoWithReadOnlyProperty), Properties = [] }, ], EnumTypes = [] }; @@ -563,56 +571,6 @@ public void MarshalToJson_MarshalsDto() Assert.Equal(10, jsonObj["count"]?.GetValue()); } - [Fact] - public void JsonOptions_ContainsJsonStringEnumConverter() - { - var options = AtsMarshaller.JsonOptions; - - Assert.Contains(options.Converters, c => c is System.Text.Json.Serialization.JsonStringEnumConverter); - } - - [Fact] - public void MarshalToJson_MarshalsDtoWithEnumPropertyAsString() - { - var marshaller = CreateMarshaller(); - var dto = new TestDtoWithEnum { Label = "item", Status = TestEnum.ValueB }; - - var result = marshaller.MarshalToJson(dto); - - Assert.NotNull(result); - Assert.IsType(result); - var jsonObj = (JsonObject)result; - Assert.Equal("item", jsonObj["label"]?.GetValue()); - Assert.Equal("ValueB", jsonObj["status"]?.GetValue()); - } - - [Fact] - public void UnmarshalFromJson_UnmarshalsDtoWithEnumPropertyFromString() - { - var (marshaller, context) = CreateMarshallerWithContext(); - var json = new JsonObject { ["label"] = "item", ["status"] = "ValueA" }; - - var result = marshaller.UnmarshalFromJson(json, typeof(TestDtoWithEnum), context); - - Assert.NotNull(result); - var dto = Assert.IsType(result); - Assert.Equal("item", dto.Label); - Assert.Equal(TestEnum.ValueA, dto.Status); - } - - [Fact] - public void UnmarshalFromJson_UnmarshalsDtoWithEnumPropertyCaseInsensitive() - { - var (marshaller, context) = CreateMarshallerWithContext(); - var json = new JsonObject { ["label"] = "test", ["status"] = "valueb" }; - - var result = marshaller.UnmarshalFromJson(json, typeof(TestDtoWithEnum), context); - - Assert.NotNull(result); - var dto = Assert.IsType(result); - Assert.Equal(TestEnum.ValueB, dto.Status); - } - [Fact] public void UnmarshalFromJson_UnmarshalsEnumFromString() { @@ -679,6 +637,201 @@ private static (AtsMarshaller Marshaller, AtsMarshaller.UnmarshalContext Context return (marshaller, context); } + [Fact] + public void MarshalToJson_HandlesDirectCircularReference() + { + var marshaller = CreateMarshaller(); + var dto = new SelfReferencingDto { Name = "root" }; + dto.Self = dto; + + var result = marshaller.MarshalToJson(dto); + + Assert.NotNull(result); + var obj = Assert.IsType(result); + Assert.Equal("root", obj["name"]!.GetValue()); + Assert.True(obj["self"] is null || obj["self"]!.GetValueKind() == System.Text.Json.JsonValueKind.Null); + } + + [Fact] + public void MarshalToJson_HandlesMutualCircularReference() + { + var marshaller = CreateMarshaller(); + var parent = new ParentDto { Label = "parent" }; + var child = new ChildDto { Label = "child", Parent = parent }; + parent.Child = child; + + var result = marshaller.MarshalToJson(parent); + + Assert.NotNull(result); + var obj = Assert.IsType(result); + Assert.Equal("parent", obj["label"]!.GetValue()); + var childObj = Assert.IsType(obj["child"]); + Assert.Equal("child", childObj["label"]!.GetValue()); + // The back-reference to parent should be null (cycle broken) + Assert.True(childObj["parent"] is null || childObj["parent"]!.GetValueKind() == System.Text.Json.JsonValueKind.Null); + } + + [Fact] + public void MarshalToJson_HandlesCircularReferenceWithTypeRef() + { + var marshaller = CreateMarshaller(); + var dto = new SelfReferencingDto { Name = "typed" }; + dto.Self = dto; + + var typeRef = new AtsTypeRef { TypeId = "test/SelfReferencingDto", Category = AtsTypeCategory.Dto }; + + var result = marshaller.MarshalToJson(dto, typeRef); + + Assert.NotNull(result); + var obj = Assert.IsType(result); + Assert.Equal("typed", obj["name"]!.GetValue()); + Assert.True(obj["self"] is null || obj["self"]!.GetValueKind() == System.Text.Json.JsonValueKind.Null); + } + + [Fact] + public void MarshalToJson_PreservesNonCircularNestedDtos() + { + var marshaller = CreateMarshaller(); + var parent = new ParentDto { Label = "parent" }; + var child = new ChildDto { Label = "child", Parent = null }; + parent.Child = child; + + var result = marshaller.MarshalToJson(parent); + + Assert.NotNull(result); + var obj = Assert.IsType(result); + Assert.Equal("parent", obj["label"]!.GetValue()); + var childObj = Assert.IsType(obj["child"]); + Assert.Equal("child", childObj["label"]!.GetValue()); + Assert.True(childObj["parent"] is null || childObj["parent"]!.GetValueKind() == System.Text.Json.JsonValueKind.Null); + } + + [Fact] + public void ApplyDtoProperties_UpdatesWritableProperties() + { + var marshaller = CreateMarshaller(); + var dto = new TestDto { Name = "original", Count = 0 }; + var source = new JsonObject { ["name"] = "updated", ["count"] = 42 }; + + marshaller.ApplyDtoProperties(source, dto, typeof(TestDto)); + + Assert.Equal("updated", dto.Name); + Assert.Equal(42, dto.Count); + } + + [Fact] + public void ApplyDtoProperties_OnlyUpdatesProvidedProperties() + { + var marshaller = CreateMarshaller(); + var dto = new TestDto { Name = "original", Count = 10 }; + var source = new JsonObject { ["name"] = "updated" }; + + marshaller.ApplyDtoProperties(source, dto, typeof(TestDto)); + + Assert.Equal("updated", dto.Name); + Assert.Equal(10, dto.Count); // Count unchanged since not in JSON + } + + [Fact] + public void ApplyDtoProperties_SkipsNonDeserializableProperties() + { + var marshaller = CreateMarshaller(); + var dto = new DtoWithComplexProperty { Name = "original", Complex = new NonDeserializableType("keep-me") }; + var source = new JsonObject + { + ["name"] = "updated", + ["complex"] = new JsonObject { ["value"] = "should-be-ignored" } + }; + + marshaller.ApplyDtoProperties(source, dto, typeof(DtoWithComplexProperty)); + + Assert.Equal("updated", dto.Name); + Assert.Equal("keep-me", dto.Complex.Value); // Complex property unchanged + } + + [Fact] + public void ApplyDtoProperties_RespectsJsonPropertyName() + { + var marshaller = CreateMarshaller(); + var dto = new DtoWithJsonPropertyName { DisplayName = "original", Value = 0 }; + var source = new JsonObject { ["display_name"] = "updated", ["val"] = 99 }; + + marshaller.ApplyDtoProperties(source, dto, typeof(DtoWithJsonPropertyName)); + + Assert.Equal("updated", dto.DisplayName); + Assert.Equal(99, dto.Value); + } + + [Fact] + public void ApplyDtoProperties_RespectsJsonPropertyName_IgnoresCamelCaseKey() + { + var marshaller = CreateMarshaller(); + var dto = new DtoWithJsonPropertyName { DisplayName = "original", Value = 5 }; + // Use camelCase CLR name instead of the [JsonPropertyName] — should NOT match + var source = new JsonObject { ["displayName"] = "should-not-apply" }; + + marshaller.ApplyDtoProperties(source, dto, typeof(DtoWithJsonPropertyName)); + + Assert.Equal("original", dto.DisplayName); + } + + [Fact] + public void ApplyDtoProperties_RespectsJsonIgnore() + { + var marshaller = CreateMarshaller(); + var dto = new DtoWithJsonIgnore { Name = "original", Secret = "keep-me" }; + var source = new JsonObject { ["name"] = "updated", ["secret"] = "should-be-ignored" }; + + marshaller.ApplyDtoProperties(source, dto, typeof(DtoWithJsonIgnore)); + + Assert.Equal("updated", dto.Name); + Assert.Equal("keep-me", dto.Secret); // JsonIgnore property unchanged + } + + [Fact] + public void ApplyDtoProperties_SkipsReadOnlyProperties() + { + var marshaller = CreateMarshaller(); + var dto = new DtoWithReadOnlyProperty { Name = "original" }; + var source = new JsonObject { ["name"] = "updated", ["computed"] = "should-be-ignored" }; + + marshaller.ApplyDtoProperties(source, dto, typeof(DtoWithReadOnlyProperty)); + + Assert.Equal("updated", dto.Name); + Assert.Equal("read-only", dto.Computed); // Read-only property unchanged + } + + [Fact] + public void ApplyDtoProperties_SkipsIncompatibleJsonValues() + { + var marshaller = CreateMarshaller(); + var dto = new TestDto { Name = "original", Count = 10 }; + // Send a string for an int property — should be silently skipped + var source = new JsonObject { ["count"] = "not-a-number" }; + + marshaller.ApplyDtoProperties(source, dto, typeof(TestDto)); + + Assert.Equal("original", dto.Name); + Assert.Equal(10, dto.Count); // Count unchanged due to incompatible value + } + + [Fact] + public void IsDtoType_ReturnsTrueForRegisteredDtoType() + { + var marshaller = CreateMarshaller(); + + Assert.True(marshaller.IsDtoType(typeof(TestDto))); + } + + [Fact] + public void IsDtoType_ReturnsFalseForNonDtoType() + { + var marshaller = CreateMarshaller(); + + Assert.False(marshaller.IsDtoType(typeof(string))); + Assert.False(marshaller.IsDtoType(typeof(TestClass))); + } + private enum TestEnum { ValueA, @@ -703,4 +856,69 @@ private sealed class TestDtoWithEnum public string? Label { get; set; } public TestEnum Status { get; set; } } + + [AspireDto] + private sealed class SelfReferencingDto + { + public string? Name { get; set; } + public SelfReferencingDto? Self { get; set; } + } + + [AspireDto] + private sealed class ParentDto + { + public string? Label { get; set; } + public ChildDto? Child { get; set; } + } + + [AspireDto] + private sealed class ChildDto + { + public string? Label { get; set; } + public ParentDto? Parent { get; set; } + } + + [AspireDto] + private sealed class DtoWithComplexProperty + { + public string? Name { get; set; } + public NonDeserializableType Complex { get; set; } = new("default"); + } + + /// + /// A type that cannot be deserialized by System.Text.Json (multiple parameterized constructors, none annotated). + /// Simulates EndpointReference in ResourceUrlAnnotation. + /// + private sealed class NonDeserializableType + { + public string Value { get; } + public NonDeserializableType(string value) => Value = value; + public NonDeserializableType(string value, int extra) => Value = value + extra; + } + + [AspireDto] + private sealed class DtoWithJsonPropertyName + { + [JsonPropertyName("display_name")] + public string? DisplayName { get; set; } + + [JsonPropertyName("val")] + public int Value { get; set; } + } + + [AspireDto] + private sealed class DtoWithJsonIgnore + { + public string? Name { get; set; } + + [JsonIgnore] + public string? Secret { get; set; } + } + + [AspireDto] + private sealed class DtoWithReadOnlyProperty + { + public string? Name { get; set; } + public string Computed { get; } = "read-only"; + } } diff --git a/tests/Aspire.Hosting.RemoteHost.Tests/CallbackProxyTests.cs b/tests/Aspire.Hosting.RemoteHost.Tests/CallbackProxyTests.cs index 74cd38c18bc..93fcb8a9088 100644 --- a/tests/Aspire.Hosting.RemoteHost.Tests/CallbackProxyTests.cs +++ b/tests/Aspire.Hosting.RemoteHost.Tests/CallbackProxyTests.cs @@ -223,11 +223,132 @@ public async Task InvokedProxy_PropagatesOperationCanceledException() await Assert.ThrowsAsync(() => proxy()); } - private static AtsCallbackProxyFactory CreateFactory(ICallbackInvoker? invoker = null) + [Fact] + public void InvokedSyncVoidProxy_AppliesDtoWritebackFromResult() + { + var dto = new TestCallbackDto { Name = "original", Count = 0 }; + + // The invoker returns the modified args (simulating TypeScript returning mutated DTO) + var invoker = new TestCallbackInvoker + { + ResultToReturn = new JsonObject + { + ["p0"] = new JsonObject { ["name"] = "modified", ["count"] = 42 } + } + }; + using var factory = CreateFactory(invoker, registerDtoTypes: true); + + var proxy = (TestSyncVoidCallbackWithDto)factory.CreateProxy("test-callback", typeof(TestSyncVoidCallbackWithDto))!; + + proxy(dto); + + Assert.Equal("modified", dto.Name); + Assert.Equal(42, dto.Count); + } + + [Fact] + public async Task InvokedAsyncVoidProxy_AppliesDtoWritebackFromResult() + { + var dto = new TestCallbackDto { Name = "original", Count = 0 }; + + var invoker = new TestCallbackInvoker + { + ResultToReturn = new JsonObject + { + ["p0"] = new JsonObject { ["name"] = "async-modified", ["count"] = 99 } + } + }; + using var factory = CreateFactory(invoker, registerDtoTypes: true); + + var proxy = (TestAsyncVoidCallbackWithDto)factory.CreateProxy("test-callback", typeof(TestAsyncVoidCallbackWithDto))!; + + await proxy(dto); + + Assert.Equal("async-modified", dto.Name); + Assert.Equal(99, dto.Count); + } + + [Fact] + public void InvokedSyncVoidProxy_DtoWritebackIgnoresNonDtoArgs() + { + // Use a delegate with both a non-DTO param (string) and a DTO param to exercise + // the writeback path. The non-DTO arg at p0 should be safely skipped, while + // the DTO arg at p1 should be written back. + var dto = new TestCallbackDto { Name = "original", Count = 0 }; + var invoker = new TestCallbackInvoker + { + ResultToReturn = new JsonObject + { + ["p0"] = JsonValue.Create("some-string"), + ["p1"] = new JsonObject { ["name"] = "mixed-modified", ["count"] = 77 } + } + }; + using var factory = CreateFactory(invoker, registerDtoTypes: true); + + var proxy = (TestSyncVoidCallbackWithMixedArgs)factory.CreateProxy("test-callback", typeof(TestSyncVoidCallbackWithMixedArgs))!; + + // Should not throw - non-DTO arg at p0 is skipped, DTO arg at p1 is written back + proxy("hello", dto); + + Assert.Equal("mixed-modified", dto.Name); + Assert.Equal(77, dto.Count); + } + + [Fact] + public void InvokedSyncVoidProxy_DtoWritebackHandlesNullResult() + { + var dto = new TestCallbackDto { Name = "original", Count = 0 }; + + // Invoker returns null (TypeScript callback returned undefined and no args were sent back) + var invoker = new TestCallbackInvoker { ResultToReturn = null }; + using var factory = CreateFactory(invoker, registerDtoTypes: true); + + var proxy = (TestSyncVoidCallbackWithDto)factory.CreateProxy("test-callback", typeof(TestSyncVoidCallbackWithDto))!; + + proxy(dto); + + // Original values should be unchanged + Assert.Equal("original", dto.Name); + Assert.Equal(0, dto.Count); + } + + [Fact] + public void InvokedSyncVoidProxy_AppliesWritebackToMultipleDtos() + { + var dto1 = new TestCallbackDto { Name = "first", Count = 1 }; + var dto2 = new TestCallbackDto { Name = "second", Count = 2 }; + + var invoker = new TestCallbackInvoker + { + ResultToReturn = new JsonObject + { + ["p0"] = new JsonObject { ["name"] = "first-updated", ["count"] = 10 }, + ["p1"] = new JsonObject { ["name"] = "second-updated", ["count"] = 20 } + } + }; + using var factory = CreateFactory(invoker, registerDtoTypes: true); + + var proxy = (TestSyncVoidCallbackWithMultipleDtos)factory.CreateProxy("test-callback", typeof(TestSyncVoidCallbackWithMultipleDtos))!; + + proxy(dto1, dto2); + + Assert.Equal("first-updated", dto1.Name); + Assert.Equal(10, dto1.Count); + Assert.Equal("second-updated", dto2.Name); + Assert.Equal(20, dto2.Count); + } + + private static AtsCallbackProxyFactory CreateFactory(ICallbackInvoker? invoker = null, bool registerDtoTypes = false) { var handles = new HandleRegistry(); var ctRegistry = new CancellationTokenRegistry(); - var context = new AtsContext { Capabilities = [], HandleTypes = [], DtoTypes = [], EnumTypes = [] }; + var dtoTypes = registerDtoTypes + ? new List + { + new() { TypeId = "test/TestCallbackDto", Name = "TestCallbackDto", ClrType = typeof(TestCallbackDto), Properties = [] } + } + : []; + var context = new AtsContext { Capabilities = [], HandleTypes = [], DtoTypes = dtoTypes, EnumTypes = [] }; var marshaller = new AtsMarshaller(handles, context, ctRegistry, new Lazy(() => throw new NotImplementedException())); return new AtsCallbackProxyFactory(invoker ?? new TestCallbackInvoker(), handles, ctRegistry, marshaller); } @@ -246,6 +367,21 @@ private static AtsCallbackProxyFactory CreateFactory(ICallbackInvoker? invoker = public delegate Task TestCallbackWithStringResult(string input); public delegate Task TestCallbackWithCancellation(string value, CancellationToken cancellationToken); + + public delegate void TestSyncVoidCallbackWithDto(TestCallbackDto dto); + + public delegate Task TestAsyncVoidCallbackWithDto(TestCallbackDto dto); + + public delegate void TestSyncVoidCallbackWithMixedArgs(string label, TestCallbackDto dto); + + public delegate void TestSyncVoidCallbackWithMultipleDtos(TestCallbackDto dto1, TestCallbackDto dto2); + + [AspireDto] + public sealed class TestCallbackDto + { + public string? Name { get; set; } + public int Count { get; set; } + } } internal sealed class TestCallbackInvoker : ICallbackInvoker diff --git a/tests/Aspire.Hosting.RemoteHost.Tests/CapabilityDispatcherTests.cs b/tests/Aspire.Hosting.RemoteHost.Tests/CapabilityDispatcherTests.cs index 40becadefb4..fefb5188628 100644 --- a/tests/Aspire.Hosting.RemoteHost.Tests/CapabilityDispatcherTests.cs +++ b/tests/Aspire.Hosting.RemoteHost.Tests/CapabilityDispatcherTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Nodes; +using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Ats; using Aspire.Hosting.RemoteHost.Ats; using Xunit; @@ -1200,6 +1201,120 @@ public void GetDto_ReturnsNullWhenPropertyMissing() Assert.Null(result); } + // Builder-to-resource unwrapping tests + // These test the scenario where a handle contains an IResourceBuilder but the + // property/method being invoked is declared on the resource type T. + // This happens in TypeScript polyglot apps when ATS maps both IResourceBuilder + // and T to the same type ID. + [Fact] + public void Invoke_PropertyGetter_ResolvesBuilderToResource() + { + var handles = new HandleRegistry(); + var dispatcher = new CapabilityDispatcher(handles, CreateTestMarshaller(handles), [typeof(TestResourceWithProperties).Assembly]); + + // Create a resource and wrap it in a builder, but register the BUILDER in the handle registry + var resource = new TestResourceWithProperties("test-resource") { Color = "blue" }; + var builder = new TestResourceBuilder(resource); + var handleId = handles.Register(builder, "Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.TestResourceWithProperties"); + var args = new JsonObject { ["context"] = new JsonObject { ["$handle"] = handleId } }; + + // Invoke the property getter - the property is on TestResourceWithProperties, but handle contains the builder + var result = dispatcher.Invoke("Aspire.Hosting.RemoteHost.Tests/TestResourceWithProperties.color", args); + + Assert.NotNull(result); + Assert.Equal("blue", result.GetValue()); + } + + [Fact] + public void Invoke_PropertySetter_ResolvesBuilderToResource() + { + var handles = new HandleRegistry(); + var dispatcher = new CapabilityDispatcher(handles, CreateTestMarshaller(handles), [typeof(TestResourceWithProperties).Assembly]); + + var resource = new TestResourceWithProperties("test-resource") { Color = "red" }; + var builder = new TestResourceBuilder(resource); + var handleId = handles.Register(builder, "Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.TestResourceWithProperties"); + var args = new JsonObject + { + ["context"] = new JsonObject { ["$handle"] = handleId }, + ["value"] = "green" + }; + + dispatcher.Invoke("Aspire.Hosting.RemoteHost.Tests/TestResourceWithProperties.setColor", args); + + Assert.Equal("green", resource.Color); + } + + [Fact] + public void Invoke_InstanceMethod_ResolvesBuilderToResource() + { + var handles = new HandleRegistry(); + var dispatcher = new CapabilityDispatcher(handles, CreateTestMarshaller(handles), [typeof(TestResourceWithMethods).Assembly]); + + var resource = new TestResourceWithMethods("test-resource"); + var builder = new TestResourceBuilder(resource); + var handleId = handles.Register(builder, "Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.TestResourceWithMethods"); + var args = new JsonObject + { + ["context"] = new JsonObject { ["$handle"] = handleId }, + ["prefix"] = "hello" + }; + + var result = dispatcher.Invoke("Aspire.Hosting.RemoteHost.Tests/TestResourceWithMethods.greet", args); + + Assert.NotNull(result); + Assert.Equal("hello, test-resource!", result.GetValue()); + } + + [Fact] + public void Invoke_PropertyGetter_WorksDirectlyOnResource() + { + var handles = new HandleRegistry(); + var dispatcher = new CapabilityDispatcher(handles, CreateTestMarshaller(handles), [typeof(TestResourceWithProperties).Assembly]); + + // When the handle contains the resource directly (not wrapped in a builder), it should still work + var resource = new TestResourceWithProperties("test-resource") { Color = "yellow" }; + var handleId = handles.Register(resource, "Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.TestResourceWithProperties"); + var args = new JsonObject { ["context"] = new JsonObject { ["$handle"] = handleId } }; + + var result = dispatcher.Invoke("Aspire.Hosting.RemoteHost.Tests/TestResourceWithProperties.color", args); + + Assert.NotNull(result); + Assert.Equal("yellow", result.GetValue()); + } + + [Fact] + public void Invoke_PropertyGetter_ResolvesInheritedPropertyViaBuilder() + { + var handles = new HandleRegistry(); + var dispatcher = new CapabilityDispatcher(handles, CreateTestMarshaller(handles), [typeof(TestResourceWithProperties).Assembly]); + + var resource = new TestResourceWithProperties("my-resource") { Color = "red" }; + var builder = new TestResourceBuilder(resource); + var handleId = handles.Register(builder, "Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.TestResourceWithProperties"); + var args = new JsonObject { ["context"] = new JsonObject { ["$handle"] = handleId } }; + + var result = dispatcher.Invoke("Aspire.Hosting.RemoteHost.Tests/TestResourceWithProperties.name", args); + + Assert.NotNull(result); + Assert.Equal("my-resource", result.GetValue()); + } + + [Fact] + public void Invoke_PropertyGetter_ThrowsWhenHandleIsUnrelatedType() + { + var handles = new HandleRegistry(); + var dispatcher = new CapabilityDispatcher(handles, CreateTestMarshaller(handles), [typeof(TestResourceWithProperties).Assembly]); + + var handleId = handles.Register("not-a-resource", "Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.TestResourceWithProperties"); + var args = new JsonObject { ["context"] = new JsonObject { ["$handle"] = handleId } }; + + var ex = Assert.Throws(() => + dispatcher.Invoke("Aspire.Hosting.RemoteHost.Tests/TestResourceWithProperties.color", args)); + + Assert.Equal(AtsErrorCodes.InternalError, ex.Error.Code); + } + private static CapabilityDispatcher CreateDispatcher(params System.Reflection.Assembly[] assemblies) { var handles = new HandleRegistry(); @@ -1487,3 +1602,45 @@ internal sealed class TestDtoWithEnum public string? Label { get; set; } public TestDispatchEnum Status { get; set; } } + +/// +/// A minimal IResourceBuilder implementation for testing builder-to-resource unwrapping. +/// +internal sealed class TestResourceBuilder : IResourceBuilder where T : IResource +{ + public TestResourceBuilder(T resource) + { + Resource = resource; + } + + public T Resource { get; } + public IDistributedApplicationBuilder ApplicationBuilder => throw new NotImplementedException(); + + public IResourceBuilder WithAnnotation(TAnnotation annotation, ResourceAnnotationMutationBehavior behavior = ResourceAnnotationMutationBehavior.Append) where TAnnotation : IResourceAnnotation + => throw new NotImplementedException(); +} + +/// +/// Test resource type with properties that should be accessible via builder handles. +/// +[AspireExport(ExposeProperties = true)] +internal sealed class TestResourceWithProperties : Resource +{ + public TestResourceWithProperties(string name) : base(name) { } + + public string Color { get; set; } = "default"; +} + +/// +/// Test resource type with instance methods that should be accessible via builder handles. +/// +[AspireExport(ExposeMethods = true)] +internal sealed class TestResourceWithMethods : Resource +{ + public TestResourceWithMethods(string name) : base(name) { } + + public string Greet(string prefix) + { + return $"{prefix}, {Name}!"; + } +} diff --git a/tests/Aspire.Hosting.Tests/Backchannel/AuxiliaryBackchannelRpcTargetTests.cs b/tests/Aspire.Hosting.Tests/Backchannel/AuxiliaryBackchannelRpcTargetTests.cs index 14a7c9e11d1..307c67d583f 100644 --- a/tests/Aspire.Hosting.Tests/Backchannel/AuxiliaryBackchannelRpcTargetTests.cs +++ b/tests/Aspire.Hosting.Tests/Backchannel/AuxiliaryBackchannelRpcTargetTests.cs @@ -118,9 +118,9 @@ await notificationService.PublishUpdateAsync(custom.Resource, s => s with new EnvironmentVariableSnapshot("ANOTHER_VAR", "another-value", true) ], Commands = [ - new ResourceCommandSnapshot("resource-start", ResourceCommandState.Enabled, "Start", "Start the resource", null, null, null, null, false), - new ResourceCommandSnapshot("resource-stop", ResourceCommandState.Disabled, "Stop", "Stop the resource", null, null, null, null, false), - new ResourceCommandSnapshot("resource-restart", ResourceCommandState.Hidden, "Restart", null, null, null, null, null, true) + new ResourceCommandSnapshot("start", ResourceCommandState.Enabled, "Start", "Start the resource", null, null, null, null, false), + new ResourceCommandSnapshot("stop", ResourceCommandState.Disabled, "Stop", "Stop the resource", null, null, null, null, false), + new ResourceCommandSnapshot("restart", ResourceCommandState.Hidden, "Restart", null, null, null, null, null, true) ], Properties = [ new ResourcePropertySnapshot(CustomResourceKnownProperties.Source, "normal-value"), @@ -183,9 +183,9 @@ await notificationService.PublishUpdateAsync(custom.Resource, s => s with // Commands Assert.Equal(3, snapshot.Commands.Length); - Assert.Contains(snapshot.Commands, c => c.Name == "resource-start" && c.DisplayName == "Start" && c.Description == "Start the resource" && c.State == "Enabled"); - Assert.Contains(snapshot.Commands, c => c.Name == "resource-stop" && c.DisplayName == "Stop" && c.Description == "Stop the resource" && c.State == "Disabled"); - Assert.Contains(snapshot.Commands, c => c.Name == "resource-restart" && c.DisplayName == "Restart" && c.Description == null && c.State == "Hidden"); + Assert.Contains(snapshot.Commands, c => c.Name == "start" && c.DisplayName == "Start" && c.Description == "Start the resource" && c.State == "Enabled"); + Assert.Contains(snapshot.Commands, c => c.Name == "stop" && c.DisplayName == "Stop" && c.Description == "Stop the resource" && c.State == "Disabled"); + Assert.Contains(snapshot.Commands, c => c.Name == "restart" && c.DisplayName == "Restart" && c.Description == null && c.State == "Hidden"); // Properties (sensitive values should be redacted) Assert.True(snapshot.Properties.TryGetValue(CustomResourceKnownProperties.Source, out var normalValue)); diff --git a/tests/Aspire.Hosting.Tests/ResourceCommandAnnotationTests.cs b/tests/Aspire.Hosting.Tests/ResourceCommandAnnotationTests.cs index fd3b9d1c46a..ddfd580db3a 100644 --- a/tests/Aspire.Hosting.Tests/ResourceCommandAnnotationTests.cs +++ b/tests/Aspire.Hosting.Tests/ResourceCommandAnnotationTests.cs @@ -10,39 +10,39 @@ namespace Aspire.Hosting.Tests; public class ResourceCommandAnnotationTests { [Theory] - [InlineData("resource-start", "Starting", ResourceCommandState.Disabled)] - [InlineData("resource-start", "Stopping", ResourceCommandState.Hidden)] - [InlineData("resource-start", "Running", ResourceCommandState.Hidden)] - [InlineData("resource-start", "Exited", ResourceCommandState.Enabled)] - [InlineData("resource-start", "Finished", ResourceCommandState.Enabled)] - [InlineData("resource-start", "FailedToStart", ResourceCommandState.Enabled)] - [InlineData("resource-start", "Unknown", ResourceCommandState.Enabled)] - [InlineData("resource-start", "Waiting", ResourceCommandState.Enabled)] - [InlineData("resource-start", "RuntimeUnhealthy", ResourceCommandState.Disabled)] - [InlineData("resource-start", "", ResourceCommandState.Disabled)] - [InlineData("resource-start", null, ResourceCommandState.Disabled)] - [InlineData("resource-stop", "Starting", ResourceCommandState.Hidden)] - [InlineData("resource-stop", "Stopping", ResourceCommandState.Disabled)] - [InlineData("resource-stop", "Running", ResourceCommandState.Enabled)] - [InlineData("resource-stop", "Exited", ResourceCommandState.Hidden)] - [InlineData("resource-stop", "Finished", ResourceCommandState.Hidden)] - [InlineData("resource-stop", "FailedToStart", ResourceCommandState.Hidden)] - [InlineData("resource-stop", "Unknown", ResourceCommandState.Hidden)] - [InlineData("resource-stop", "Waiting", ResourceCommandState.Hidden)] - [InlineData("resource-stop", "RuntimeUnhealthy", ResourceCommandState.Hidden)] - [InlineData("resource-stop", "", ResourceCommandState.Hidden)] - [InlineData("resource-stop", null, ResourceCommandState.Hidden)] - [InlineData("resource-restart", "Starting", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "Stopping", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "Running", ResourceCommandState.Enabled)] - [InlineData("resource-restart", "Exited", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "Finished", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "FailedToStart", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "Unknown", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "Waiting", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "RuntimeUnhealthy", ResourceCommandState.Disabled)] - [InlineData("resource-restart", "", ResourceCommandState.Disabled)] - [InlineData("resource-restart", null, ResourceCommandState.Disabled)] + [InlineData("start", "Starting", ResourceCommandState.Disabled)] + [InlineData("start", "Stopping", ResourceCommandState.Hidden)] + [InlineData("start", "Running", ResourceCommandState.Hidden)] + [InlineData("start", "Exited", ResourceCommandState.Enabled)] + [InlineData("start", "Finished", ResourceCommandState.Enabled)] + [InlineData("start", "FailedToStart", ResourceCommandState.Enabled)] + [InlineData("start", "Unknown", ResourceCommandState.Enabled)] + [InlineData("start", "Waiting", ResourceCommandState.Enabled)] + [InlineData("start", "RuntimeUnhealthy", ResourceCommandState.Disabled)] + [InlineData("start", "", ResourceCommandState.Disabled)] + [InlineData("start", null, ResourceCommandState.Disabled)] + [InlineData("stop", "Starting", ResourceCommandState.Hidden)] + [InlineData("stop", "Stopping", ResourceCommandState.Disabled)] + [InlineData("stop", "Running", ResourceCommandState.Enabled)] + [InlineData("stop", "Exited", ResourceCommandState.Hidden)] + [InlineData("stop", "Finished", ResourceCommandState.Hidden)] + [InlineData("stop", "FailedToStart", ResourceCommandState.Hidden)] + [InlineData("stop", "Unknown", ResourceCommandState.Hidden)] + [InlineData("stop", "Waiting", ResourceCommandState.Hidden)] + [InlineData("stop", "RuntimeUnhealthy", ResourceCommandState.Hidden)] + [InlineData("stop", "", ResourceCommandState.Hidden)] + [InlineData("stop", null, ResourceCommandState.Hidden)] + [InlineData("restart", "Starting", ResourceCommandState.Disabled)] + [InlineData("restart", "Stopping", ResourceCommandState.Disabled)] + [InlineData("restart", "Running", ResourceCommandState.Enabled)] + [InlineData("restart", "Exited", ResourceCommandState.Disabled)] + [InlineData("restart", "Finished", ResourceCommandState.Disabled)] + [InlineData("restart", "FailedToStart", ResourceCommandState.Disabled)] + [InlineData("restart", "Unknown", ResourceCommandState.Disabled)] + [InlineData("restart", "Waiting", ResourceCommandState.Disabled)] + [InlineData("restart", "RuntimeUnhealthy", ResourceCommandState.Disabled)] + [InlineData("restart", "", ResourceCommandState.Disabled)] + [InlineData("restart", null, ResourceCommandState.Disabled)] public void LifeCycleCommands_CommandState(string commandName, string? resourceState, ResourceCommandState commandState) { // Arrange diff --git a/tests/Aspire.Hosting.Tests/ResourceCommandServiceTests.cs b/tests/Aspire.Hosting.Tests/ResourceCommandServiceTests.cs index b87a2ab8fd6..971b6566452 100644 --- a/tests/Aspire.Hosting.Tests/ResourceCommandServiceTests.cs +++ b/tests/Aspire.Hosting.Tests/ResourceCommandServiceTests.cs @@ -326,6 +326,48 @@ public async Task ExecuteCommandAsync_OperationCanceledException_Canceled() Assert.Null(result.ErrorMessage); } + [Fact] + public async Task ExecuteCommandAsync_LegacyCommandName_FallsBackToCurrentName() + { + // Arrange + using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper); + + var custom = builder.AddResource(new CustomResource("myResource")); + custom.WithCommand(name: KnownResourceCommands.StartCommand, + displayName: "Start", + executeCommand: _ => Task.FromResult(new ExecuteCommandResult { Success = true })); + + var app = builder.Build(); + await app.StartAsync(); + + // Act - use the legacy "resource-start" name + var result = await app.ResourceCommands.ExecuteCommandAsync(custom.Resource, "resource-start"); + + // Assert - should succeed via fallback + Assert.True(result.Success); + } + + [Fact] + public async Task ExecuteCommandAsync_LegacyCommandName_ById_FallsBackToCurrentName() + { + // Arrange + using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper); + + var custom = builder.AddResource(new CustomResource("myResource")); + custom.WithCommand(name: KnownResourceCommands.StopCommand, + displayName: "Stop", + executeCommand: _ => Task.FromResult(new ExecuteCommandResult { Success = true })); + + var app = builder.Build(); + await app.StartAsync(); + + // Act - use the legacy "resource-stop" name via resource ID + var result = await app.ResourceCommands.ExecuteCommandAsync("myResource", "resource-stop"); + + // Assert - should succeed via fallback + Assert.True(result.Success); + } + private sealed class CustomResource(string name) : Resource(name), IResourceWithEndpoints, IResourceWithWaitSupport {