diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.aspire/settings.json new file mode 100644 index 00000000000..66a4c4f3e5a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,8 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "Aspire.Hosting.Azure.AppContainers": "", + "Aspire.Hosting.Azure.OperationalInsights": "" + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/.codegen-hash b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/.codegen-hash new file mode 100644 index 00000000000..508e43e71fa --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/.codegen-hash @@ -0,0 +1 @@ +BFDBEE79E391368156C929FBA3E89038416E658D6130E0C7BE7C4AE69BF97E8D \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/aspire.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/aspire.ts new file mode 100644 index 00000000000..ee93868876b --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/aspire.ts @@ -0,0 +1,5859 @@ +// 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 AzureContainerAppEnvironmentResource */ +type AzureContainerAppEnvironmentResourceHandle = Handle<'Aspire.Hosting.Azure.AppContainers/Aspire.Hosting.Azure.AppContainers.AzureContainerAppEnvironmentResource'>; + +/** Handle to AzureLogAnalyticsWorkspaceResource */ +type AzureLogAnalyticsWorkspaceResourceHandle = Handle<'Aspire.Hosting.Azure.OperationalInsights/Aspire.Hosting.Azure.AzureLogAnalyticsWorkspaceResource'>; + +/** Handle to AzureResourceInfrastructure */ +type AzureResourceInfrastructureHandle = Handle<'Aspire.Hosting.Azure/Aspire.Hosting.Azure.AzureResourceInfrastructure'>; + +/** 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 IComputeResource */ +type IComputeResourceHandle = Handle<'Aspire.Hosting/Aspire.Hosting.ApplicationModel.IComputeResource'>; + +/** 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 ContainerApp */ +type ContainerAppHandle = Handle<'Azure.Provisioning.AppContainers/Azure.Provisioning.AppContainers.ContainerApp'>; + +/** Handle to ContainerAppJob */ +type ContainerAppJobHandle = Handle<'Azure.Provisioning.AppContainers/Azure.Provisioning.AppContainers.ContainerAppJob'>; + +/** 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 PublishAsConfiguredScheduledAzureContainerAppJobOptions { + configure?: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise; +} + +export interface RunOptions { + cancellationToken?: AbortSignal; +} + +export interface WaitForCompletionOptions { + exitCode?: number; +} + +export interface WithBindMountOptions { + isReadOnly?: boolean; +} + +export interface WithCommandOptions { + commandOptions?: CommandOptions; +} + +export interface WithDashboardOptions { + enable?: 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 WithHttpsUpgradeOptions { + upgrade?: 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 Container App Environment resource */ + /** @internal */ + async _addAzureContainerAppEnvironmentInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/addAzureContainerAppEnvironment', + rpcArgs + ); + return new AzureContainerAppEnvironmentResource(result, this._client); + } + + addAzureContainerAppEnvironment(name: string): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._addAzureContainerAppEnvironmentInternal(name)); + } + + /** Adds an Azure Log Analytics Workspace resource */ + /** @internal */ + async _addAzureLogAnalyticsWorkspaceInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.OperationalInsights/addAzureLogAnalyticsWorkspace', + rpcArgs + ); + return new AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + addAzureLogAnalyticsWorkspace(name: string): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._addAzureLogAnalyticsWorkspaceInternal(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 Container App Environment resource */ + addAzureContainerAppEnvironment(name: string): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.addAzureContainerAppEnvironment(name))); + } + + /** Adds an Azure Log Analytics Workspace resource */ + addAzureLogAnalyticsWorkspace(name: string): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.addAzureLogAnalyticsWorkspace(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))); + } + +} + +// ============================================================================ +// AzureContainerAppEnvironmentResource +// ============================================================================ + +export class AzureContainerAppEnvironmentResource extends ResourceBuilderBase { + constructor(handle: AzureContainerAppEnvironmentResourceHandle, 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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureContainerAppEnvironmentResourcePromise { + const displayText = options?.displayText; + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureContainerAppEnvironmentResourcePromise { + const displayText = options?.displayText; + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureContainerAppEnvironmentResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureContainerAppEnvironmentResourcePromise(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 AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(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 _withAzdResourceNamingInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/withAzdResourceNaming', + rpcArgs + ); + return new AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Configures resources to use azd naming conventions */ + withAzdResourceNaming(): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._withAzdResourceNamingInternal()); + } + + /** @internal */ + private async _withCompactResourceNamingInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/withCompactResourceNaming', + rpcArgs + ); + return new AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Configures resources to use compact naming for length-constrained Azure resources */ + withCompactResourceNaming(): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._withCompactResourceNamingInternal()); + } + + /** @internal */ + private async _withDashboardInternal(enable?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (enable !== undefined) rpcArgs.enable = enable; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/withDashboard', + rpcArgs + ); + return new AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Configures whether the Aspire dashboard is included in the container app environment */ + withDashboard(options?: WithDashboardOptions): AzureContainerAppEnvironmentResourcePromise { + const enable = options?.enable; + return new AzureContainerAppEnvironmentResourcePromise(this._withDashboardInternal(enable)); + } + + /** @internal */ + private async _withHttpsUpgradeInternal(upgrade?: boolean): Promise { + const rpcArgs: Record = { builder: this._handle }; + if (upgrade !== undefined) rpcArgs.upgrade = upgrade; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/withHttpsUpgrade', + rpcArgs + ); + return new AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Configures whether HTTP endpoints are upgraded to HTTPS */ + withHttpsUpgrade(options?: WithHttpsUpgradeOptions): AzureContainerAppEnvironmentResourcePromise { + const upgrade = options?.upgrade; + return new AzureContainerAppEnvironmentResourcePromise(this._withHttpsUpgradeInternal(upgrade)); + } + + /** @internal */ + private async _withAzureLogAnalyticsWorkspaceInternal(workspaceBuilder: AzureLogAnalyticsWorkspaceResource): Promise { + const rpcArgs: Record = { builder: this._handle, workspaceBuilder }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/withAzureLogAnalyticsWorkspace', + rpcArgs + ); + return new AzureContainerAppEnvironmentResource(result, this._client); + } + + /** Configures the container app environment to use a specific Log Analytics Workspace */ + withAzureLogAnalyticsWorkspace(workspaceBuilder: AzureLogAnalyticsWorkspaceResource): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._withAzureLogAnalyticsWorkspaceInternal(workspaceBuilder)); + } + +} + +/** + * Thenable wrapper for AzureContainerAppEnvironmentResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureContainerAppEnvironmentResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureContainerAppEnvironmentResource) => 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): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** Gets the resource name */ + getResourceName(): Promise { + return this._promise.then(obj => obj.getResourceName()); + } + + /** Configures resources to use azd naming conventions */ + withAzdResourceNaming(): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withAzdResourceNaming())); + } + + /** Configures resources to use compact naming for length-constrained Azure resources */ + withCompactResourceNaming(): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withCompactResourceNaming())); + } + + /** Configures whether the Aspire dashboard is included in the container app environment */ + withDashboard(options?: WithDashboardOptions): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withDashboard(options))); + } + + /** Configures whether HTTP endpoints are upgraded to HTTPS */ + withHttpsUpgrade(options?: WithHttpsUpgradeOptions): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withHttpsUpgrade(options))); + } + + /** Configures the container app environment to use a specific Log Analytics Workspace */ + withAzureLogAnalyticsWorkspace(workspaceBuilder: AzureLogAnalyticsWorkspaceResource): AzureContainerAppEnvironmentResourcePromise { + return new AzureContainerAppEnvironmentResourcePromise(this._promise.then(obj => obj.withAzureLogAnalyticsWorkspace(workspaceBuilder))); + } + +} + +// ============================================================================ +// AzureLogAnalyticsWorkspaceResource +// ============================================================================ + +export class AzureLogAnalyticsWorkspaceResource extends ResourceBuilderBase { + constructor(handle: AzureLogAnalyticsWorkspaceResourceHandle, 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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Customizes displayed URLs via callback */ + withUrlsCallback(callback: (obj: ResourceUrlsCallbackContext) => Promise): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureLogAnalyticsWorkspaceResourcePromise { + const displayText = options?.displayText; + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureLogAnalyticsWorkspaceResourcePromise { + const displayText = options?.displayText; + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureLogAnalyticsWorkspaceResourcePromise { + const commandOptions = options?.commandOptions; + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource(result, this._client); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(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 AzureLogAnalyticsWorkspaceResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class AzureLogAnalyticsWorkspaceResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: AzureLogAnalyticsWorkspaceResource) => 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): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withUrlsCallback(callback))); + } + + /** Customizes displayed URLs via async callback */ + withUrlsCallbackAsync(callback: (arg: ResourceUrlsCallbackContext) => Promise): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withUrlsCallbackAsync(callback))); + } + + /** Adds or modifies displayed URLs */ + withUrl(url: string, options?: WithUrlOptions): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withUrl(url, options))); + } + + /** Adds a URL using a reference expression */ + withUrlExpression(url: ReferenceExpression, options?: WithUrlExpressionOptions): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withUrlExpression(url, options))); + } + + /** Customizes the URL for a specific endpoint via callback */ + withUrlForEndpoint(endpointName: string, callback: (obj: ResourceUrlAnnotation) => Promise): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withUrlForEndpoint(endpointName, callback))); + } + + /** Prevents resource from starting automatically */ + withExplicitStart(): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withExplicitStart())); + } + + /** Adds a health check by key */ + withHealthCheck(key: string): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withHealthCheck(key))); + } + + /** Adds a resource command */ + withCommand(name: string, displayName: string, executeCommand: (arg: ExecuteCommandContext) => Promise, options?: WithCommandOptions): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withCommand(name, displayName, executeCommand, options))); + } + + /** Sets the parent relationship */ + withParentRelationship(parent: ResourceBuilderBase): AzureLogAnalyticsWorkspaceResourcePromise { + return new AzureLogAnalyticsWorkspaceResourcePromise(this._promise.then(obj => obj.withParentRelationship(parent))); + } + + /** 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 _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 _publishAsAzureContainerAppInternal(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): Promise { + const configureId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppHandle; + await configure(arg1, arg2); + }); + const rpcArgs: Record = { container: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishContainerAsAzureContainerApp', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures the container resource to be published as an Azure Container App */ + publishAsAzureContainerApp(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._publishAsAzureContainerAppInternal(configure)); + } + + /** @internal */ + private async _publishAsConfiguredAzureContainerAppJobInternal(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }); + const rpcArgs: Record = { resource: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredAzureContainerAppJob', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._publishAsConfiguredAzureContainerAppJobInternal(configure)); + } + + /** @internal */ + private async _publishAsAzureContainerAppJobInternal(): Promise { + const rpcArgs: Record = { resource: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsAzureContainerAppJob', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ContainerResourcePromise { + return new ContainerResourcePromise(this._publishAsAzureContainerAppJobInternal()); + } + + /** @internal */ + private async _publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression: string, configure?: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = configure ? registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }) : undefined; + const rpcArgs: Record = { resource: this._handle, cronExpression }; + if (configure !== undefined) rpcArgs.configure = configureId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredScheduledAzureContainerAppJob', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ContainerResourcePromise { + const configure = options?.configure; + return new ContainerResourcePromise(this._publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression, configure)); + } + + /** @internal */ + private async _publishAsScheduledAzureContainerAppJobInternal(cronExpression: string): Promise { + const rpcArgs: Record = { resource: this._handle, cronExpression }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsScheduledAzureContainerAppJob', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._publishAsScheduledAzureContainerAppJobInternal(cronExpression)); + } + +} + +/** + * 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()); + } + + /** Configures the container resource to be published as an Azure Container App */ + publishAsAzureContainerApp(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.publishAsAzureContainerApp(configure))); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.publishAsConfiguredAzureContainerAppJob(configure))); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.publishAsAzureContainerAppJob())); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.publishAsConfiguredScheduledAzureContainerAppJob(cronExpression, options))); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.publishAsScheduledAzureContainerAppJob(cronExpression))); + } + +} + +// ============================================================================ +// 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 _publishAsAzureContainerAppInternal(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): Promise { + const configureId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppHandle; + await configure(arg1, arg2); + }); + const rpcArgs: Record = { executable: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishExecutableAsAzureContainerApp', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures the executable resource to be published as an Azure Container App */ + publishAsAzureContainerApp(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._publishAsAzureContainerAppInternal(configure)); + } + + /** @internal */ + private async _publishAsConfiguredAzureContainerAppJobInternal(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }); + const rpcArgs: Record = { resource: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredAzureContainerAppJob', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._publishAsConfiguredAzureContainerAppJobInternal(configure)); + } + + /** @internal */ + private async _publishAsAzureContainerAppJobInternal(): Promise { + const rpcArgs: Record = { resource: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsAzureContainerAppJob', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._publishAsAzureContainerAppJobInternal()); + } + + /** @internal */ + private async _publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression: string, configure?: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = configure ? registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }) : undefined; + const rpcArgs: Record = { resource: this._handle, cronExpression }; + if (configure !== undefined) rpcArgs.configure = configureId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredScheduledAzureContainerAppJob', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ExecutableResourcePromise { + const configure = options?.configure; + return new ExecutableResourcePromise(this._publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression, configure)); + } + + /** @internal */ + private async _publishAsScheduledAzureContainerAppJobInternal(cronExpression: string): Promise { + const rpcArgs: Record = { resource: this._handle, cronExpression }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsScheduledAzureContainerAppJob', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._publishAsScheduledAzureContainerAppJobInternal(cronExpression)); + } + +} + +/** + * 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()); + } + + /** Configures the executable resource to be published as an Azure Container App */ + publishAsAzureContainerApp(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.publishAsAzureContainerApp(configure))); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.publishAsConfiguredAzureContainerAppJob(configure))); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.publishAsAzureContainerAppJob())); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.publishAsConfiguredScheduledAzureContainerAppJob(cronExpression, options))); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.publishAsScheduledAzureContainerAppJob(cronExpression))); + } + +} + +// ============================================================================ +// 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 + ); + } + + /** @internal */ + private async _publishAsAzureContainerAppInternal(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): Promise { + const configureId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppHandle; + await configure(arg1, arg2); + }); + const rpcArgs: Record = { project: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishProjectAsAzureContainerApp', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures the project resource to be published as an Azure Container App */ + publishAsAzureContainerApp(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._publishAsAzureContainerAppInternal(configure)); + } + + /** @internal */ + private async _publishAsConfiguredAzureContainerAppJobInternal(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }); + const rpcArgs: Record = { resource: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredAzureContainerAppJob', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._publishAsConfiguredAzureContainerAppJobInternal(configure)); + } + + /** @internal */ + private async _publishAsAzureContainerAppJobInternal(): Promise { + const rpcArgs: Record = { resource: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsAzureContainerAppJob', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ProjectResourcePromise { + return new ProjectResourcePromise(this._publishAsAzureContainerAppJobInternal()); + } + + /** @internal */ + private async _publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression: string, configure?: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = configure ? registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }) : undefined; + const rpcArgs: Record = { resource: this._handle, cronExpression }; + if (configure !== undefined) rpcArgs.configure = configureId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredScheduledAzureContainerAppJob', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ProjectResourcePromise { + const configure = options?.configure; + return new ProjectResourcePromise(this._publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression, configure)); + } + + /** @internal */ + private async _publishAsScheduledAzureContainerAppJobInternal(cronExpression: string): Promise { + const rpcArgs: Record = { resource: this._handle, cronExpression }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsScheduledAzureContainerAppJob', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._publishAsScheduledAzureContainerAppJobInternal(cronExpression)); + } + +} + +/** + * 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()); + } + + /** Configures the project resource to be published as an Azure Container App */ + publishAsAzureContainerApp(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppHandle) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.publishAsAzureContainerApp(configure))); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.publishAsConfiguredAzureContainerAppJob(configure))); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.publishAsAzureContainerAppJob())); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.publishAsConfiguredScheduledAzureContainerAppJob(cronExpression, options))); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.publishAsScheduledAzureContainerAppJob(cronExpression))); + } + +} + +// ============================================================================ +// ComputeResource +// ============================================================================ + +export class ComputeResource extends ResourceBuilderBase { + constructor(handle: IComputeResourceHandle, client: AspireClientRpc) { + super(handle, client); + } + + /** @internal */ + private async _publishAsConfiguredAzureContainerAppJobInternal(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }); + const rpcArgs: Record = { resource: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredAzureContainerAppJob', + rpcArgs + ); + return new ComputeResource(result, this._client); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ComputeResourcePromise { + return new ComputeResourcePromise(this._publishAsConfiguredAzureContainerAppJobInternal(configure)); + } + + /** @internal */ + private async _publishAsAzureContainerAppJobInternal(): Promise { + const rpcArgs: Record = { resource: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsAzureContainerAppJob', + rpcArgs + ); + return new ComputeResource(result, this._client); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ComputeResourcePromise { + return new ComputeResourcePromise(this._publishAsAzureContainerAppJobInternal()); + } + + /** @internal */ + private async _publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression: string, configure?: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): Promise { + const configureId = configure ? registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1 = wrapIfHandle(args.p0) as AzureResourceInfrastructureHandle; + const arg2 = wrapIfHandle(args.p1) as ContainerAppJobHandle; + await configure(arg1, arg2); + }) : undefined; + const rpcArgs: Record = { resource: this._handle, cronExpression }; + if (configure !== undefined) rpcArgs.configure = configureId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsConfiguredScheduledAzureContainerAppJob', + rpcArgs + ); + return new ComputeResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ComputeResourcePromise { + const configure = options?.configure; + return new ComputeResourcePromise(this._publishAsConfiguredScheduledAzureContainerAppJobInternal(cronExpression, configure)); + } + + /** @internal */ + private async _publishAsScheduledAzureContainerAppJobInternal(cronExpression: string): Promise { + const rpcArgs: Record = { resource: this._handle, cronExpression }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.Azure.AppContainers/publishAsScheduledAzureContainerAppJob', + rpcArgs + ); + return new ComputeResource(result, this._client); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ComputeResourcePromise { + return new ComputeResourcePromise(this._publishAsScheduledAzureContainerAppJobInternal(cronExpression)); + } + +} + +/** + * Thenable wrapper for ComputeResource that enables fluent chaining. + * @example + * await builder.addSomething().withX().withY(); + */ +export class ComputeResourcePromise implements PromiseLike { + constructor(private _promise: Promise) {} + + then( + onfulfilled?: ((value: ComputeResource) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): PromiseLike { + return this._promise.then(onfulfilled, onrejected); + } + + /** Configures the compute resource as an Azure Container App Job with custom configuration */ + publishAsConfiguredAzureContainerAppJob(configure: (arg1: AzureResourceInfrastructureHandle, arg2: ContainerAppJobHandle) => Promise): ComputeResourcePromise { + return new ComputeResourcePromise(this._promise.then(obj => obj.publishAsConfiguredAzureContainerAppJob(configure))); + } + + /** Configures the compute resource as a manually triggered Azure Container App Job */ + publishAsAzureContainerAppJob(): ComputeResourcePromise { + return new ComputeResourcePromise(this._promise.then(obj => obj.publishAsAzureContainerAppJob())); + } + + /** Configures the compute resource as a scheduled Azure Container App Job with custom configuration */ + publishAsConfiguredScheduledAzureContainerAppJob(cronExpression: string, options?: PublishAsConfiguredScheduledAzureContainerAppJobOptions): ComputeResourcePromise { + return new ComputeResourcePromise(this._promise.then(obj => obj.publishAsConfiguredScheduledAzureContainerAppJob(cronExpression, options))); + } + + /** Configures the compute resource as a scheduled Azure Container App Job */ + publishAsScheduledAzureContainerAppJob(cronExpression: string): ComputeResourcePromise { + return new ComputeResourcePromise(this._promise.then(obj => obj.publishAsScheduledAzureContainerAppJob(cronExpression))); + } + +} + +// ============================================================================ +// 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.AppContainers/Aspire.Hosting.Azure.AppContainers.AzureContainerAppEnvironmentResource', (handle, client) => new AzureContainerAppEnvironmentResource(handle as AzureContainerAppEnvironmentResourceHandle, client)); +registerHandleWrapper('Aspire.Hosting.Azure.OperationalInsights/Aspire.Hosting.Azure.AzureLogAnalyticsWorkspaceResource', (handle, client) => new AzureLogAnalyticsWorkspaceResource(handle as AzureLogAnalyticsWorkspaceResourceHandle, 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.IComputeResource', (handle, client) => new ComputeResource(handle as IComputeResourceHandle, 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.AppContainers/ValidationAppHost/.modules/base.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/base.ts new file mode 100644 index 00000000000..d25499d7b82 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/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.AppContainers/ValidationAppHost/.modules/transport.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/.modules/transport.ts new file mode 100644 index 00000000000..6b9a4acae98 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/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.AppContainers/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/apphost.run.json new file mode 100644 index 00000000000..2c361f7f93d --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "https": { + "applicationUrl": "https://localhost:49511;http://localhost:51415", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:48887", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:33229" + } + } + } +} \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/apphost.ts new file mode 100644 index 00000000000..d0005c68846 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/apphost.ts @@ -0,0 +1,68 @@ +// Aspire TypeScript AppHost - Validation for Aspire.Hosting.Azure.AppContainers +// For more information, see: https://aspire.dev + +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// === Azure Container App Environment === +// Test addAzureContainerAppEnvironment factory method +const env = builder.addAzureContainerAppEnvironment("myenv"); + +// Test fluent chaining on AzureContainerAppEnvironmentResource +await env + .withAzdResourceNaming() + .withCompactResourceNaming() + .withDashboard({ enable: true }) + .withHttpsUpgrade({ upgrade: false }); + +// Test withDashboard with no args (uses default) +const env2 = builder.addAzureContainerAppEnvironment("myenv2"); +await env2.withDashboard(); + +// Test withHttpsUpgrade with no args (uses default) +await env2.withHttpsUpgrade(); + +// === WithAzureLogAnalyticsWorkspace === +// Test withAzureLogAnalyticsWorkspace with a Log Analytics Workspace resource +const laws = await builder.addAzureLogAnalyticsWorkspace("laws"); +const env3 = builder.addAzureContainerAppEnvironment("myenv3"); +await env3.withAzureLogAnalyticsWorkspace(laws); + +// === PublishAsAzureContainerApp === +// Test publishAsAzureContainerApp on a container resource with callback +const web = builder.addContainer("web", "myregistry/web:latest"); +await web.publishAsAzureContainerApp(async (infrastructure, app) => { + // Configure container app via callback +}); + +// Test publishAsAzureContainerApp on an executable resource +const api = builder.addExecutable("api", "dotnet", ".", ["run"]); +await api.publishAsAzureContainerApp(async (infrastructure, app) => { + // Configure container app for executable +}); + +// === PublishAsAzureContainerAppJob === +// Test publishAsAzureContainerAppJob (parameterless - manual trigger) +const worker = builder.addContainer("worker", "myregistry/worker:latest"); +await worker.publishAsAzureContainerAppJob(); + +// Test publishAsConfiguredAzureContainerAppJob (with callback) +const processor = builder.addContainer("processor", "myregistry/processor:latest"); +await processor.publishAsConfiguredAzureContainerAppJob(async (infrastructure, job) => { + // Configure the container app job here +}); + +// Test publishAsScheduledAzureContainerAppJob (simple - no callback) +const scheduler = builder.addContainer("scheduler", "myregistry/scheduler:latest"); +await scheduler.publishAsScheduledAzureContainerAppJob("0 0 * * *"); + +// Test publishAsConfiguredScheduledAzureContainerAppJob (with callback) +const reporter = builder.addContainer("reporter", "myregistry/reporter:latest"); +await reporter.publishAsConfiguredScheduledAzureContainerAppJob("0 */6 * * *", { + configure: async (infrastructure, job) => { + // Configure the scheduled job here + } +}); + +await builder.build().run(); \ No newline at end of file diff --git a/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/package-lock.json new file mode 100644 index 00000000000..2679fa17689 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/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.AppContainers/ValidationAppHost/package.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/package.json new file mode 100644 index 00000000000..be16934198a --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/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.AppContainers/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/ValidationAppHost/tsconfig.json new file mode 100644 index 00000000000..edf7302cc25 --- /dev/null +++ b/playground/polyglot/TypeScript/Aspire.Hosting.Azure.AppContainers/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.Hosting.Azure.AppContainers/AtsTypeMappings.cs b/src/Aspire.Hosting.Azure.AppContainers/AtsTypeMappings.cs new file mode 100644 index 00000000000..a95f710ee5e --- /dev/null +++ b/src/Aspire.Hosting.Azure.AppContainers/AtsTypeMappings.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. + +using Aspire.Hosting; +using Azure.Provisioning.AppContainers; + +// ============================================================================ +// ATS Type Exports for Aspire.Hosting.Azure.AppContainers +// ============================================================================ +// These assembly-level attributes mark external types as ATS exports so they +// can be used as callback context parameters in polyglot app hosts. + +[assembly: AspireExport(typeof(ContainerApp), ExposeProperties = true)] +[assembly: AspireExport(typeof(ContainerAppJob), ExposeProperties = true)] diff --git a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppContainerExtensions.cs b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppContainerExtensions.cs index b104ea13212..611f5f1041c 100644 --- a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppContainerExtensions.cs +++ b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppContainerExtensions.cs @@ -31,6 +31,7 @@ public static class AzureContainerAppContainerExtensions /// /// /// + [AspireExport("publishContainerAsAzureContainerApp", MethodName = "publishAsAzureContainerApp", Description = "Configures the container resource to be published as an Azure Container App")] public static IResourceBuilder PublishAsAzureContainerApp(this IResourceBuilder container, Action configure) where T : ContainerResource { diff --git a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExecutableExtensions.cs b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExecutableExtensions.cs index f9488bb0408..7d16b796941 100644 --- a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExecutableExtensions.cs +++ b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExecutableExtensions.cs @@ -31,6 +31,7 @@ public static class AzureContainerAppExecutableExtensions /// /// /// + [AspireExport("publishExecutableAsAzureContainerApp", MethodName = "publishAsAzureContainerApp", Description = "Configures the executable resource to be published as an Azure Container App")] public static IResourceBuilder PublishAsAzureContainerApp(this IResourceBuilder executable, Action configure) where T : ExecutableResource { diff --git a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExtensions.cs b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExtensions.cs index e9352549ffd..d3276388db7 100644 --- a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExtensions.cs +++ b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExtensions.cs @@ -56,6 +56,7 @@ internal static IDistributedApplicationBuilder AddAzureContainerAppsInfrastructu /// The distributed application builder. /// The name of the resource. /// + [AspireExport("addAzureContainerAppEnvironment", Description = "Adds an Azure Container App Environment resource")] public static IResourceBuilder AddAzureContainerAppEnvironment(this IDistributedApplicationBuilder builder, string name) { builder.AddAzureContainerAppsInfrastructureCore(); @@ -409,6 +410,7 @@ public static IResourceBuilder AddAzureCon /// This method allows for reusing the previously deployed resources if the application was deployed using /// azd without calling /// + [AspireExport("withAzdResourceNaming", Description = "Configures resources to use azd naming conventions")] public static IResourceBuilder WithAzdResourceNaming(this IResourceBuilder builder) { builder.Resource.UseAzdNamingConvention = true; @@ -438,6 +440,7 @@ public static IResourceBuilder WithAzdReso /// Use to change those names as well. /// /// + [AspireExport("withCompactResourceNaming", Description = "Configures resources to use compact naming for length-constrained Azure resources")] [Experimental("ASPIREACANAMING001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public static IResourceBuilder WithCompactResourceNaming(this IResourceBuilder builder) { @@ -451,6 +454,7 @@ public static IResourceBuilder WithCompact /// The AzureContainerAppEnvironmentResource to configure. /// Whether to include the Aspire dashboard. Default is true. /// + [AspireExport("withDashboard", Description = "Configures whether the Aspire dashboard is included in the container app environment")] public static IResourceBuilder WithDashboard(this IResourceBuilder builder, bool enable = true) { builder.Resource.EnableDashboard = enable; @@ -469,6 +473,7 @@ public static IResourceBuilder WithDashboa /// Note that explicit ports specified for development (e.g., port 8080) are still normalized /// to standard ports (80/443) as required by Azure Container Apps. /// + [AspireExport("withHttpsUpgrade", Description = "Configures whether HTTP endpoints are upgraded to HTTPS")] public static IResourceBuilder WithHttpsUpgrade(this IResourceBuilder builder, bool upgrade = true) { builder.Resource.PreserveHttpEndpoints = !upgrade; @@ -482,6 +487,7 @@ public static IResourceBuilder WithHttpsUp /// The resource builder for the to use. /// /// Thrown when or is null. + [AspireExport("withAzureLogAnalyticsWorkspace", Description = "Configures the container app environment to use a specific Log Analytics Workspace")] public static IResourceBuilder WithAzureLogAnalyticsWorkspace(this IResourceBuilder builder, IResourceBuilder workspaceBuilder) { ArgumentNullException.ThrowIfNull(builder); diff --git a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppProjectExtensions.cs b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppProjectExtensions.cs index ff00e3a8650..8e05d88f337 100644 --- a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppProjectExtensions.cs +++ b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppProjectExtensions.cs @@ -31,6 +31,7 @@ public static class AzureContainerAppProjectExtensions /// /// /// + [AspireExport("publishProjectAsAzureContainerApp", MethodName = "publishAsAzureContainerApp", Description = "Configures the project resource to be published as an Azure Container App")] public static IResourceBuilder PublishAsAzureContainerApp(this IResourceBuilder project, Action configure) where T : ProjectResource { diff --git a/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs b/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs index 6a1877ebef6..6834d8a1ec6 100644 --- a/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs +++ b/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs @@ -53,7 +53,9 @@ public static class ContainerAppExtensions /// }); /// /// + /// This method is not available in polyglot app hosts. /// + [AspireExportIgnore(Reason = "Extends ContainerApp (Azure.Provisioning type) which is not an IResourceBuilder target, so the ATS codegen cannot generate a wrapper class for it.")] [Experimental("ASPIREACADOMAINS001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public static void ConfigureCustomDomain(this ContainerApp app, IResourceBuilder customDomain, IResourceBuilder certificateName) { @@ -147,7 +149,9 @@ public static void ConfigureCustomDomain(this ContainerApp app, IResourceBuilder /// }); /// /// + /// This overload allows custom configuration of the container app job via a callback. /// + [AspireExport("publishAsConfiguredAzureContainerAppJob", Description = "Configures the compute resource as an Azure Container App Job with custom configuration")] [Experimental("ASPIREAZURE002", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public static IResourceBuilder PublishAsAzureContainerAppJob(this IResourceBuilder resource, Action configure) where T : IComputeResource @@ -185,6 +189,7 @@ public static IResourceBuilder PublishAsAzureContainerAppJob(this IResourc /// /// /// + [AspireExport("publishAsAzureContainerAppJob", Description = "Configures the compute resource as a manually triggered Azure Container App Job")] [Experimental("ASPIREAZURE002", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public static IResourceBuilder PublishAsAzureContainerAppJob(this IResourceBuilder resource) where T : IComputeResource @@ -216,7 +221,9 @@ public static IResourceBuilder PublishAsAzureContainerAppJob(this IResourc /// .PublishAsScheduledAzureContainerAppJob("0 0 * * *"); // Run every day at midnight /// /// + /// This overload allows custom configuration of the scheduled container app job via a callback. /// + [AspireExport("publishAsConfiguredScheduledAzureContainerAppJob", Description = "Configures the compute resource as a scheduled Azure Container App Job with custom configuration")] [Experimental("ASPIREAZURE002", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public static IResourceBuilder PublishAsScheduledAzureContainerAppJob(this IResourceBuilder resource, string cronExpression, Action? configure = null) where T : IComputeResource @@ -232,4 +239,22 @@ public static IResourceBuilder PublishAsScheduledAzureContainerAppJob(this configure?.Invoke(infrastructure, job); }); } + + /// + /// Configures the specified compute resource as a scheduled Azure Container App Job with the provided cron expression. + /// + /// The type of the compute resource. + /// The compute resource builder. + /// The cron expression that defines the schedule for the job. + /// The updated compute resource builder. + /// + /// This method is a convenience wrapper that configures the job with a schedule trigger using the specified cron expression. + /// + [AspireExport("publishAsScheduledAzureContainerAppJob", Description = "Configures the compute resource as a scheduled Azure Container App Job")] + [Experimental("ASPIREAZURE002", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] + internal static IResourceBuilder PublishAsScheduledAzureContainerAppJob(this IResourceBuilder resource, string cronExpression) + where T : IComputeResource + { + return resource.PublishAsScheduledAzureContainerAppJob(cronExpression, configure: null); + } } diff --git a/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs b/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs index 5396171d0ca..381ce02d66f 100644 --- a/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs +++ b/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs @@ -9,6 +9,7 @@ namespace Aspire.Hosting.Azure; /// /// An Azure Provisioning which represents the root Bicep module that is generated for an Azure resource. /// +[AspireExport(ExposeProperties = true)] public sealed class AzureResourceInfrastructure : Infrastructure { internal AzureResourceInfrastructure(AzureProvisioningResource resource, string name) : base(name) diff --git a/src/Aspire.Hosting.CodeGeneration.Go/AtsGoCodeGenerator.cs b/src/Aspire.Hosting.CodeGeneration.Go/AtsGoCodeGenerator.cs index e41233e868a..d6372258a5e 100644 --- a/src/Aspire.Hosting.CodeGeneration.Go/AtsGoCodeGenerator.cs +++ b/src/Aspire.Hosting.CodeGeneration.Go/AtsGoCodeGenerator.cs @@ -534,8 +534,9 @@ private IReadOnlyList BuildHandleTypes(AtsContext context) var handleTypeIds = new HashSet(StringComparer.Ordinal); foreach (var handleType in context.HandleTypes) { - // Skip ReferenceExpression - it's defined in base.go - if (handleType.AtsTypeId == AtsConstants.ReferenceExpressionTypeId) + // Skip ReferenceExpression and CancellationToken - they're defined in base.go/transport.go + if (handleType.AtsTypeId == AtsConstants.ReferenceExpressionTypeId + || IsCancellationTokenTypeId(handleType.AtsTypeId)) { continue; } @@ -705,7 +706,11 @@ AtsConstants.DateTime or AtsConstants.DateTimeOffset or }; private static bool IsCancellationToken(AtsParameterInfo parameter) => - parameter.Type?.TypeId == AtsConstants.CancellationToken; + IsCancellationTokenTypeId(parameter.Type?.TypeId); + + private static bool IsCancellationTokenTypeId(string? typeId) => + string.Equals(typeId, AtsConstants.CancellationToken, StringComparison.Ordinal) + || (typeId?.EndsWith("/System.Threading.CancellationToken", StringComparison.Ordinal) ?? false); private static void AddHandleTypeIfNeeded(HashSet handleTypeIds, AtsTypeRef? typeRef) { @@ -714,8 +719,9 @@ private static void AddHandleTypeIfNeeded(HashSet handleTypeIds, AtsType return; } - // Skip ReferenceExpression - it's defined in base.go - if (typeRef.TypeId == AtsConstants.ReferenceExpressionTypeId) + // Skip ReferenceExpression and CancellationToken - they're defined in base.go/transport.go + if (typeRef.TypeId == AtsConstants.ReferenceExpressionTypeId + || IsCancellationTokenTypeId(typeRef.TypeId)) { return; } diff --git a/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs b/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs index 050a449bc0f..a69814b8ef7 100644 --- a/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs +++ b/src/Aspire.Hosting.CodeGeneration.Java/AtsJavaCodeGenerator.cs @@ -501,8 +501,9 @@ private IReadOnlyList BuildHandleTypes(AtsContext context) var handleTypeIds = new HashSet(StringComparer.Ordinal); foreach (var handleType in context.HandleTypes) { - // Skip ReferenceExpression - it's defined in Base.java - if (handleType.AtsTypeId == AtsConstants.ReferenceExpressionTypeId) + // Skip ReferenceExpression and CancellationToken - they're defined in Base.java/Transport.java + if (handleType.AtsTypeId == AtsConstants.ReferenceExpressionTypeId + || IsCancellationTokenTypeId(handleType.AtsTypeId)) { continue; } @@ -669,7 +670,11 @@ AtsConstants.DateTime or AtsConstants.DateTimeOffset or }; private static bool IsCancellationToken(AtsParameterInfo parameter) => - parameter.Type?.TypeId == AtsConstants.CancellationToken; + IsCancellationTokenTypeId(parameter.Type?.TypeId); + + private static bool IsCancellationTokenTypeId(string? typeId) => + string.Equals(typeId, AtsConstants.CancellationToken, StringComparison.Ordinal) + || (typeId?.EndsWith("/System.Threading.CancellationToken", StringComparison.Ordinal) ?? false); private static void AddHandleTypeIfNeeded(HashSet handleTypeIds, AtsTypeRef? typeRef) { @@ -678,8 +683,9 @@ private static void AddHandleTypeIfNeeded(HashSet handleTypeIds, AtsType return; } - // Skip ReferenceExpression - it's defined in Base.java - if (typeRef.TypeId == AtsConstants.ReferenceExpressionTypeId) + // Skip ReferenceExpression and CancellationToken - they're defined in Base.java/Transport.java + if (typeRef.TypeId == AtsConstants.ReferenceExpressionTypeId + || IsCancellationTokenTypeId(typeRef.TypeId)) { return; } diff --git a/src/Aspire.Hosting.CodeGeneration.Rust/AtsRustCodeGenerator.cs b/src/Aspire.Hosting.CodeGeneration.Rust/AtsRustCodeGenerator.cs index 5f5f08e6f0f..32cd3090232 100644 --- a/src/Aspire.Hosting.CodeGeneration.Rust/AtsRustCodeGenerator.cs +++ b/src/Aspire.Hosting.CodeGeneration.Rust/AtsRustCodeGenerator.cs @@ -568,8 +568,9 @@ private IReadOnlyList BuildHandleTypes(AtsContext context) var handleTypeIds = new HashSet(StringComparer.Ordinal); foreach (var handleType in context.HandleTypes) { - // Skip ReferenceExpression - it's defined in base.rs - if (handleType.AtsTypeId == AtsConstants.ReferenceExpressionTypeId) + // Skip ReferenceExpression and CancellationToken - they're defined in base.rs/transport.rs + if (handleType.AtsTypeId == AtsConstants.ReferenceExpressionTypeId + || IsCancellationTokenTypeId(handleType.AtsTypeId)) { continue; } @@ -804,10 +805,15 @@ AtsConstants.DateTime or AtsConstants.DateTimeOffset or private static bool IsHandleType(AtsTypeRef? typeRef) => typeRef?.Category == AtsTypeCategory.Handle - && typeRef.TypeId != AtsConstants.ReferenceExpressionTypeId; + && typeRef.TypeId != AtsConstants.ReferenceExpressionTypeId + && !IsCancellationTokenTypeId(typeRef.TypeId); private static bool IsCancellationToken(AtsParameterInfo parameter) => - parameter.Type?.TypeId == AtsConstants.CancellationToken; + IsCancellationTokenTypeId(parameter.Type?.TypeId); + + private static bool IsCancellationTokenTypeId(string? typeId) => + string.Equals(typeId, AtsConstants.CancellationToken, StringComparison.Ordinal) + || (typeId?.EndsWith("/System.Threading.CancellationToken", StringComparison.Ordinal) ?? false); private static void AddHandleTypeIfNeeded(HashSet handleTypeIds, AtsTypeRef? typeRef) { @@ -816,8 +822,9 @@ private static void AddHandleTypeIfNeeded(HashSet handleTypeIds, AtsType return; } - // Skip ReferenceExpression - it's defined in base.rs - if (typeRef.TypeId == AtsConstants.ReferenceExpressionTypeId) + // Skip ReferenceExpression and CancellationToken - they're defined in base.rs/transport.rs + if (typeRef.TypeId == AtsConstants.ReferenceExpressionTypeId + || IsCancellationTokenTypeId(typeRef.TypeId)) { return; } diff --git a/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs b/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs index c38b2b3df79..e53bda49992 100644 --- a/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs +++ b/src/Aspire.Hosting.CodeGeneration.TypeScript/AtsTypeScriptCodeGenerator.cs @@ -1320,9 +1320,9 @@ private void GenerateCallbackBody(AtsParameterInfo callbackParam, IReadOnlyList< { // Multi-parameter callback - .NET sends as { p0, p1, ... } var paramNames = callbackParameters.Select((p, i) => $"p{i}").ToList(); - var destructure = string.Join(", ", paramNames); + var destructureWithTypes = string.Join(", ", paramNames.Select(p => $"{p}: unknown")); - WriteLine($" const args = argsData as {{ {destructure}: unknown }};"); + WriteLine($" const args = argsData as {{ {destructureWithTypes} }};"); var callArgs = new List(); for (var i = 0; i < callbackParameters.Count; i++) diff --git a/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs b/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs index 9e51355c23c..39f44534211 100644 --- a/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs +++ b/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs @@ -270,6 +270,42 @@ private static ScanResult ScanAssemblyWithoutExpansion( types = ex.Types.Where(t => t != null).ToArray()!; } + // Process assembly-level [AspireExport(typeof(T))] attributes for cross-assembly type exports + // This enables exporting types from external assemblies (e.g., Azure.Provisioning types) + foreach (var assemblyExportAttr in assembly.GetCustomAttributes()) + { + if (assemblyExportAttr.Type is null) + { + continue; + } + + var exportedType = assemblyExportAttr.Type; + + // Register the type info for the exported type + var typeInfo = CreateTypeInfo(exportedType, assemblyExportAttr); + if (typeInfo != null) + { + typeInfos.Add(typeInfo); + } + + // If ExposeProperties or ExposeMethods, create context type capabilities + if (assemblyExportAttr.ExposeProperties || assemblyExportAttr.ExposeMethods) + { + var contextResult = CreateContextTypeCapabilities(exportedType, assemblyName); + capabilities.AddRange(contextResult.Capabilities); + diagnostics.AddRange(contextResult.Diagnostics); + + foreach (var (id, method) in contextResult.Methods) + { + methods[id] = method; + } + foreach (var (id, property) in contextResult.Properties) + { + properties[id] = property; + } + } + } + foreach (var type in types) { // Check for [AspireDto] attribute - scan DTO types for code generation @@ -522,6 +558,19 @@ private static void ResolveUnknownTypes( foreach (var param in capability.Parameters) { ResolveTypeRef(param.Type, validTypes); + + // Also resolve callback parameter types and return type + if (param.IsCallback) + { + if (param.CallbackParameters != null) + { + foreach (var cbParam in param.CallbackParameters) + { + ResolveTypeRef(cbParam.Type, validTypes); + } + } + ResolveTypeRef(param.CallbackReturnType, validTypes); + } } } } diff --git a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/AtsGeneratedAspire.verified.go b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/AtsGeneratedAspire.verified.go index 3f4614c687e..51e2d384f81 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/AtsGeneratedAspire.verified.go +++ b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/AtsGeneratedAspire.verified.go @@ -941,6 +941,21 @@ func (s *TestRedisResource) WaitForReadyAsync(timeout float64, cancellationToken return result.(*bool), nil } +// WithMultiParamHandleCallback tests multi-param callback destructuring +func (s *TestRedisResource) WithMultiParamHandleCallback(callback func(...any) any) (*TestRedisResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + if callback != nil { + reqArgs["callback"] = RegisterCallback(callback) + } + result, err := s.Client().InvokeCapability("Aspire.Hosting.CodeGeneration.Go.Tests/withMultiParamHandleCallback", reqArgs) + if err != nil { + return nil, err + } + return result.(*TestRedisResource), nil +} + // TestResourceContext wraps a handle for Aspire.Hosting.CodeGeneration.Go.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext. type TestResourceContext struct { HandleWrapperBase diff --git a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go index e4ef1ad0d66..866433c963f 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go +++ b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go @@ -2103,6 +2103,44 @@ func (s *ExecuteCommandContext) SetCancellationToken(value *CancellationToken) ( return result.(*ExecuteCommandContext), nil } +// IConfiguration wraps a handle for Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration. +type IConfiguration struct { + HandleWrapperBase +} + +// NewIConfiguration creates a new IConfiguration. +func NewIConfiguration(handle *Handle, client *AspireClient) *IConfiguration { + return &IConfiguration{ + HandleWrapperBase: NewHandleWrapperBase(handle, client), + } +} + +// GetConfigValue gets a configuration value by key +func (s *IConfiguration) GetConfigValue(key string) (*string, error) { + reqArgs := map[string]any{ + "configuration": SerializeValue(s.Handle()), + } + reqArgs["key"] = SerializeValue(key) + result, err := s.Client().InvokeCapability("Aspire.Hosting/getConfigValue", reqArgs) + if err != nil { + return nil, err + } + return result.(*string), nil +} + +// GetConnectionString gets a connection string by name +func (s *IConfiguration) GetConnectionString(name string) (*string, error) { + reqArgs := map[string]any{ + "configuration": SerializeValue(s.Handle()), + } + reqArgs["name"] = SerializeValue(name) + result, err := s.Client().InvokeCapability("Aspire.Hosting/getConnectionString", reqArgs) + if err != nil { + return nil, err + } + return result.(*string), nil +} + // IDistributedApplicationBuilder wraps a handle for Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder. type IDistributedApplicationBuilder struct { HandleWrapperBase @@ -2309,6 +2347,42 @@ func NewIDistributedApplicationResourceEvent(handle *Handle, client *AspireClien } } +// IHostEnvironment wraps a handle for Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment. +type IHostEnvironment struct { + HandleWrapperBase +} + +// NewIHostEnvironment creates a new IHostEnvironment. +func NewIHostEnvironment(handle *Handle, client *AspireClient) *IHostEnvironment { + return &IHostEnvironment{ + HandleWrapperBase: NewHandleWrapperBase(handle, client), + } +} + +// GetEnvironmentName gets the environment name +func (s *IHostEnvironment) GetEnvironmentName() (*string, error) { + reqArgs := map[string]any{ + "environment": SerializeValue(s.Handle()), + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/getEnvironmentName", reqArgs) + if err != nil { + return nil, err + } + return result.(*string), nil +} + +// IsDevelopment checks if running in Development environment +func (s *IHostEnvironment) IsDevelopment() (*bool, error) { + reqArgs := map[string]any{ + "environment": SerializeValue(s.Handle()), + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/isDevelopment", reqArgs) + if err != nil { + return nil, err + } + return result.(*bool), nil +} + // IResource wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource. type IResource struct { ResourceBuilderBase @@ -2323,13 +2397,13 @@ func NewIResource(handle *Handle, client *AspireClient) *IResource { // IResourceWithArgs wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs. type IResourceWithArgs struct { - HandleWrapperBase + ResourceBuilderBase } // NewIResourceWithArgs creates a new IResourceWithArgs. func NewIResourceWithArgs(handle *Handle, client *AspireClient) *IResourceWithArgs { return &IResourceWithArgs{ - HandleWrapperBase: NewHandleWrapperBase(handle, client), + ResourceBuilderBase: NewResourceBuilderBase(handle, client), } } @@ -2347,25 +2421,37 @@ func NewIResourceWithConnectionString(handle *Handle, client *AspireClient) *IRe // IResourceWithEndpoints wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints. type IResourceWithEndpoints struct { - HandleWrapperBase + ResourceBuilderBase } // NewIResourceWithEndpoints creates a new IResourceWithEndpoints. func NewIResourceWithEndpoints(handle *Handle, client *AspireClient) *IResourceWithEndpoints { return &IResourceWithEndpoints{ - HandleWrapperBase: NewHandleWrapperBase(handle, client), + ResourceBuilderBase: NewResourceBuilderBase(handle, client), } } // IResourceWithEnvironment wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment. type IResourceWithEnvironment struct { - HandleWrapperBase + ResourceBuilderBase } // NewIResourceWithEnvironment creates a new IResourceWithEnvironment. func NewIResourceWithEnvironment(handle *Handle, client *AspireClient) *IResourceWithEnvironment { return &IResourceWithEnvironment{ - HandleWrapperBase: NewHandleWrapperBase(handle, client), + ResourceBuilderBase: NewResourceBuilderBase(handle, client), + } +} + +// IResourceWithParent wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithParent. +type IResourceWithParent struct { + ResourceBuilderBase +} + +// NewIResourceWithParent creates a new IResourceWithParent. +func NewIResourceWithParent(handle *Handle, client *AspireClient) *IResourceWithParent { + return &IResourceWithParent{ + ResourceBuilderBase: NewResourceBuilderBase(handle, client), } } @@ -2383,16 +2469,54 @@ func NewIResourceWithServiceDiscovery(handle *Handle, client *AspireClient) *IRe // IResourceWithWaitSupport wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport. type IResourceWithWaitSupport struct { - HandleWrapperBase + ResourceBuilderBase } // NewIResourceWithWaitSupport creates a new IResourceWithWaitSupport. func NewIResourceWithWaitSupport(handle *Handle, client *AspireClient) *IResourceWithWaitSupport { return &IResourceWithWaitSupport{ + ResourceBuilderBase: NewResourceBuilderBase(handle, client), + } +} + +// IServiceProvider wraps a handle for System.ComponentModel/System.IServiceProvider. +type IServiceProvider struct { + HandleWrapperBase +} + +// NewIServiceProvider creates a new IServiceProvider. +func NewIServiceProvider(handle *Handle, client *AspireClient) *IServiceProvider { + return &IServiceProvider{ HandleWrapperBase: NewHandleWrapperBase(handle, client), } } +// GetService gets a service by ATS type ID +func (s *IServiceProvider) GetService(typeId string) (any, error) { + reqArgs := map[string]any{ + "serviceProvider": SerializeValue(s.Handle()), + } + reqArgs["typeId"] = SerializeValue(typeId) + result, err := s.Client().InvokeCapability("Aspire.Hosting/getService", reqArgs) + if err != nil { + return nil, err + } + return result, nil +} + +// GetRequiredService gets a required service by ATS type ID +func (s *IServiceProvider) GetRequiredService(typeId string) (any, error) { + reqArgs := map[string]any{ + "serviceProvider": SerializeValue(s.Handle()), + } + reqArgs["typeId"] = SerializeValue(typeId) + result, err := s.Client().InvokeCapability("Aspire.Hosting/getRequiredService", reqArgs) + if err != nil { + return nil, err + } + return result, nil +} + // ITestVaultResource wraps a handle for Aspire.Hosting.CodeGeneration.Go.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.ITestVaultResource. type ITestVaultResource struct { ResourceBuilderBase @@ -3402,6 +3526,123 @@ func (s *ProjectResource) WithCancellableOperation(operation func(...any) any) ( return result.(*IResource), nil } +// ResourceLoggerService wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService. +type ResourceLoggerService struct { + HandleWrapperBase +} + +// NewResourceLoggerService creates a new ResourceLoggerService. +func NewResourceLoggerService(handle *Handle, client *AspireClient) *ResourceLoggerService { + return &ResourceLoggerService{ + HandleWrapperBase: NewHandleWrapperBase(handle, client), + } +} + +// CompleteLog completes the log stream for a resource +func (s *ResourceLoggerService) CompleteLog(resource *IResource) error { + reqArgs := map[string]any{ + "loggerService": SerializeValue(s.Handle()), + } + reqArgs["resource"] = SerializeValue(resource) + _, err := s.Client().InvokeCapability("Aspire.Hosting/completeLog", reqArgs) + return err +} + +// CompleteLogByName completes the log stream by resource name +func (s *ResourceLoggerService) CompleteLogByName(resourceName string) error { + reqArgs := map[string]any{ + "loggerService": SerializeValue(s.Handle()), + } + reqArgs["resourceName"] = SerializeValue(resourceName) + _, err := s.Client().InvokeCapability("Aspire.Hosting/completeLogByName", reqArgs) + return err +} + +// ResourceNotificationService wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService. +type ResourceNotificationService struct { + HandleWrapperBase +} + +// NewResourceNotificationService creates a new ResourceNotificationService. +func NewResourceNotificationService(handle *Handle, client *AspireClient) *ResourceNotificationService { + return &ResourceNotificationService{ + HandleWrapperBase: NewHandleWrapperBase(handle, client), + } +} + +// WaitForResourceState waits for a resource to reach a specified state +func (s *ResourceNotificationService) WaitForResourceState(resourceName string, targetState string) error { + reqArgs := map[string]any{ + "notificationService": SerializeValue(s.Handle()), + } + reqArgs["resourceName"] = SerializeValue(resourceName) + reqArgs["targetState"] = SerializeValue(targetState) + _, err := s.Client().InvokeCapability("Aspire.Hosting/waitForResourceState", reqArgs) + return err +} + +// WaitForResourceStates waits for a resource to reach one of the specified states +func (s *ResourceNotificationService) WaitForResourceStates(resourceName string, targetStates []string) (*string, error) { + reqArgs := map[string]any{ + "notificationService": SerializeValue(s.Handle()), + } + reqArgs["resourceName"] = SerializeValue(resourceName) + reqArgs["targetStates"] = SerializeValue(targetStates) + result, err := s.Client().InvokeCapability("Aspire.Hosting/waitForResourceStates", reqArgs) + if err != nil { + return nil, err + } + return result.(*string), nil +} + +// WaitForResourceHealthy waits for a resource to become healthy +func (s *ResourceNotificationService) WaitForResourceHealthy(resourceName string) (*ResourceEventDto, error) { + reqArgs := map[string]any{ + "notificationService": SerializeValue(s.Handle()), + } + reqArgs["resourceName"] = SerializeValue(resourceName) + result, err := s.Client().InvokeCapability("Aspire.Hosting/waitForResourceHealthy", reqArgs) + if err != nil { + return nil, err + } + return result.(*ResourceEventDto), nil +} + +// WaitForDependencies waits for all dependencies of a resource to be ready +func (s *ResourceNotificationService) WaitForDependencies(resource *IResource) error { + reqArgs := map[string]any{ + "notificationService": SerializeValue(s.Handle()), + } + reqArgs["resource"] = SerializeValue(resource) + _, err := s.Client().InvokeCapability("Aspire.Hosting/waitForDependencies", reqArgs) + return err +} + +// TryGetResourceState tries to get the current state of a resource +func (s *ResourceNotificationService) TryGetResourceState(resourceName string) (*ResourceEventDto, error) { + reqArgs := map[string]any{ + "notificationService": SerializeValue(s.Handle()), + } + reqArgs["resourceName"] = SerializeValue(resourceName) + result, err := s.Client().InvokeCapability("Aspire.Hosting/tryGetResourceState", reqArgs) + if err != nil { + return nil, err + } + return result.(*ResourceEventDto), nil +} + +// PublishResourceUpdate publishes an update for a resource's state +func (s *ResourceNotificationService) PublishResourceUpdate(resource *IResource, state string, stateStyle string) error { + reqArgs := map[string]any{ + "notificationService": SerializeValue(s.Handle()), + } + reqArgs["resource"] = SerializeValue(resource) + reqArgs["state"] = SerializeValue(state) + reqArgs["stateStyle"] = SerializeValue(stateStyle) + _, err := s.Client().InvokeCapability("Aspire.Hosting/publishResourceUpdate", reqArgs) + return err +} + // ResourceUrlsCallbackContext wraps a handle for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext. type ResourceUrlsCallbackContext struct { HandleWrapperBase @@ -5326,6 +5567,21 @@ func (s *TestRedisResource) WaitForReadyAsync(timeout float64, cancellationToken return result.(*bool), nil } +// WithMultiParamHandleCallback tests multi-param callback destructuring +func (s *TestRedisResource) WithMultiParamHandleCallback(callback func(...any) any) (*TestRedisResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + if callback != nil { + reqArgs["callback"] = RegisterCallback(callback) + } + result, err := s.Client().InvokeCapability("Aspire.Hosting.CodeGeneration.Go.Tests/withMultiParamHandleCallback", reqArgs) + if err != nil { + return nil, err + } + return result.(*TestRedisResource), nil +} + // TestResourceContext wraps a handle for Aspire.Hosting.CodeGeneration.Go.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext. type TestResourceContext struct { HandleWrapperBase @@ -6225,21 +6481,72 @@ func NewUpdateCommandStateContext(handle *Handle, client *AspireClient) *UpdateC // ============================================================================ func init() { + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder", func(h *Handle, c *AspireClient) any { + return NewIDistributedApplicationBuilder(h, c) + }) RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplication", func(h *Handle, c *AspireClient) any { return NewDistributedApplication(h, c) }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext", func(h *Handle, c *AspireClient) any { - return NewDistributedApplicationExecutionContext(h, c) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference", func(h *Handle, c *AspireClient) any { + return NewEndpointReference(h, c) }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContextOptions", func(h *Handle, c *AspireClient) any { - return NewDistributedApplicationExecutionContextOptions(h, c) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource", func(h *Handle, c *AspireClient) any { + return NewIResource(h, c) }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder", func(h *Handle, c *AspireClient) any { - return NewIDistributedApplicationBuilder(h, c) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment", func(h *Handle, c *AspireClient) any { + return NewIResourceWithEnvironment(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", func(h *Handle, c *AspireClient) any { + return NewIResourceWithEndpoints(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs", func(h *Handle, c *AspireClient) any { + return NewIResourceWithArgs(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString", func(h *Handle, c *AspireClient) any { + return NewIResourceWithConnectionString(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport", func(h *Handle, c *AspireClient) any { + return NewIResourceWithWaitSupport(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithParent", func(h *Handle, c *AspireClient) any { + return NewIResourceWithParent(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource", func(h *Handle, c *AspireClient) any { + return NewContainerResource(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource", func(h *Handle, c *AspireClient) any { + return NewExecutableResource(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource", func(h *Handle, c *AspireClient) any { + return NewProjectResource(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource", func(h *Handle, c *AspireClient) any { + return NewParameterResource(h, c) + }) + RegisterHandleWrapper("System.ComponentModel/System.IServiceProvider", func(h *Handle, c *AspireClient) any { + return NewIServiceProvider(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService", func(h *Handle, c *AspireClient) any { + return NewResourceNotificationService(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService", func(h *Handle, c *AspireClient) any { + return NewResourceLoggerService(h, c) + }) + RegisterHandleWrapper("Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration", func(h *Handle, c *AspireClient) any { + return NewIConfiguration(h, c) + }) + RegisterHandleWrapper("Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment", func(h *Handle, c *AspireClient) any { + return NewIHostEnvironment(h, c) }) RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription", func(h *Handle, c *AspireClient) any { return NewDistributedApplicationEventSubscription(h, c) }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext", func(h *Handle, c *AspireClient) any { + return NewDistributedApplicationExecutionContext(h, c) + }) + RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContextOptions", func(h *Handle, c *AspireClient) any { + return NewDistributedApplicationExecutionContextOptions(h, c) + }) RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationResourceEventSubscription", func(h *Handle, c *AspireClient) any { return NewDistributedApplicationResourceEventSubscription(h, c) }) @@ -6255,9 +6562,6 @@ func init() { RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext", func(h *Handle, c *AspireClient) any { return NewCommandLineArgsCallbackContext(h, c) }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference", func(h *Handle, c *AspireClient) any { - return NewEndpointReference(h, c) - }) RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression", func(h *Handle, c *AspireClient) any { return NewEndpointReferenceExpression(h, c) }) @@ -6273,27 +6577,9 @@ func init() { RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext", func(h *Handle, c *AspireClient) any { return NewResourceUrlsCallbackContext(h, c) }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource", func(h *Handle, c *AspireClient) any { - return NewContainerResource(h, c) - }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource", func(h *Handle, c *AspireClient) any { - return NewExecutableResource(h, c) - }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource", func(h *Handle, c *AspireClient) any { - return NewParameterResource(h, c) - }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString", func(h *Handle, c *AspireClient) any { - return NewIResourceWithConnectionString(h, c) - }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource", func(h *Handle, c *AspireClient) any { - return NewProjectResource(h, c) - }) RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery", func(h *Handle, c *AspireClient) any { return NewIResourceWithServiceDiscovery(h, c) }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource", func(h *Handle, c *AspireClient) any { - return NewIResource(h, c) - }) RegisterHandleWrapper("Aspire.Hosting.CodeGeneration.Go.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestCallbackContext", func(h *Handle, c *AspireClient) any { return NewTestCallbackContext(h, c) }) @@ -6318,18 +6604,6 @@ func init() { RegisterHandleWrapper("Aspire.Hosting.CodeGeneration.Go.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.ITestVaultResource", func(h *Handle, c *AspireClient) any { return NewITestVaultResource(h, c) }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment", func(h *Handle, c *AspireClient) any { - return NewIResourceWithEnvironment(h, c) - }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs", func(h *Handle, c *AspireClient) any { - return NewIResourceWithArgs(h, c) - }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", func(h *Handle, c *AspireClient) any { - return NewIResourceWithEndpoints(h, c) - }) - RegisterHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport", func(h *Handle, c *AspireClient) any { - return NewIResourceWithWaitSupport(h, c) - }) RegisterHandleWrapper("Aspire.Hosting/Dict", func(h *Handle, c *AspireClient) any { return &AspireDict[any, any]{HandleWrapperBase: NewHandleWrapperBase(h, c)} }) diff --git a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java index 9883e04c467..4e21a9a71c7 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java +++ b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/AtsGeneratedAspire.verified.java @@ -697,6 +697,16 @@ public boolean waitForReadyAsync(double timeout, CancellationToken cancellationT return (boolean) getClient().invokeCapability("Aspire.Hosting.CodeGeneration.Java.Tests/waitForReadyAsync", reqArgs); } + /** Tests multi-param callback destructuring */ + public TestRedisResource withMultiParamHandleCallback(Function callback) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + if (callback != null) { + reqArgs.put("callback", getClient().registerCallback(callback)); + } + return (TestRedisResource) getClient().invokeCapability("Aspire.Hosting.CodeGeneration.Java.Tests/withMultiParamHandleCallback", reqArgs); + } + } /** Wrapper for Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext. */ diff --git a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java index 70dbb8b9b64..94497b86860 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java +++ b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java @@ -1756,6 +1756,30 @@ public ExecuteCommandContext setCancellationToken(CancellationToken value) { } +/** Wrapper for Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration. */ +class IConfiguration extends HandleWrapperBase { + IConfiguration(Handle handle, AspireClient client) { + super(handle, client); + } + + /** Gets a configuration value by key */ + public String getConfigValue(String key) { + Map reqArgs = new HashMap<>(); + reqArgs.put("configuration", AspireClient.serializeValue(getHandle())); + reqArgs.put("key", AspireClient.serializeValue(key)); + return (String) getClient().invokeCapability("Aspire.Hosting/getConfigValue", reqArgs); + } + + /** Gets a connection string by name */ + public String getConnectionString(String name) { + Map reqArgs = new HashMap<>(); + reqArgs.put("configuration", AspireClient.serializeValue(getHandle())); + reqArgs.put("name", AspireClient.serializeValue(name)); + return (String) getClient().invokeCapability("Aspire.Hosting/getConnectionString", reqArgs); + } + +} + /** Wrapper for Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder. */ class IDistributedApplicationBuilder extends HandleWrapperBase { IDistributedApplicationBuilder(Handle handle, AspireClient client) { @@ -1895,6 +1919,28 @@ class IDistributedApplicationResourceEvent extends HandleWrapperBase { } +/** Wrapper for Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment. */ +class IHostEnvironment extends HandleWrapperBase { + IHostEnvironment(Handle handle, AspireClient client) { + super(handle, client); + } + + /** Gets the environment name */ + public String getEnvironmentName() { + Map reqArgs = new HashMap<>(); + reqArgs.put("environment", AspireClient.serializeValue(getHandle())); + return (String) getClient().invokeCapability("Aspire.Hosting/getEnvironmentName", reqArgs); + } + + /** Checks if running in Development environment */ + public boolean isDevelopment() { + Map reqArgs = new HashMap<>(); + reqArgs.put("environment", AspireClient.serializeValue(getHandle())); + return (boolean) getClient().invokeCapability("Aspire.Hosting/isDevelopment", reqArgs); + } + +} + /** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource. */ class IResource extends ResourceBuilderBase { IResource(Handle handle, AspireClient client) { @@ -1904,7 +1950,7 @@ class IResource extends ResourceBuilderBase { } /** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs. */ -class IResourceWithArgs extends HandleWrapperBase { +class IResourceWithArgs extends ResourceBuilderBase { IResourceWithArgs(Handle handle, AspireClient client) { super(handle, client); } @@ -1920,7 +1966,7 @@ class IResourceWithConnectionString extends ResourceBuilderBase { } /** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints. */ -class IResourceWithEndpoints extends HandleWrapperBase { +class IResourceWithEndpoints extends ResourceBuilderBase { IResourceWithEndpoints(Handle handle, AspireClient client) { super(handle, client); } @@ -1928,13 +1974,21 @@ class IResourceWithEndpoints extends HandleWrapperBase { } /** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment. */ -class IResourceWithEnvironment extends HandleWrapperBase { +class IResourceWithEnvironment extends ResourceBuilderBase { IResourceWithEnvironment(Handle handle, AspireClient client) { super(handle, client); } } +/** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithParent. */ +class IResourceWithParent extends ResourceBuilderBase { + IResourceWithParent(Handle handle, AspireClient client) { + super(handle, client); + } + +} + /** Wrapper for Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery. */ class IResourceWithServiceDiscovery extends ResourceBuilderBase { IResourceWithServiceDiscovery(Handle handle, AspireClient client) { @@ -1944,13 +1998,37 @@ class IResourceWithServiceDiscovery extends ResourceBuilderBase { } /** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport. */ -class IResourceWithWaitSupport extends HandleWrapperBase { +class IResourceWithWaitSupport extends ResourceBuilderBase { IResourceWithWaitSupport(Handle handle, AspireClient client) { super(handle, client); } } +/** Wrapper for System.ComponentModel/System.IServiceProvider. */ +class IServiceProvider extends HandleWrapperBase { + IServiceProvider(Handle handle, AspireClient client) { + super(handle, client); + } + + /** Gets a service by ATS type ID */ + public Object getService(String typeId) { + Map reqArgs = new HashMap<>(); + reqArgs.put("serviceProvider", AspireClient.serializeValue(getHandle())); + reqArgs.put("typeId", AspireClient.serializeValue(typeId)); + return (Object) getClient().invokeCapability("Aspire.Hosting/getService", reqArgs); + } + + /** Gets a required service by ATS type ID */ + public Object getRequiredService(String typeId) { + Map reqArgs = new HashMap<>(); + reqArgs.put("serviceProvider", AspireClient.serializeValue(getHandle())); + reqArgs.put("typeId", AspireClient.serializeValue(typeId)); + return (Object) getClient().invokeCapability("Aspire.Hosting/getRequiredService", reqArgs); + } + +} + /** Wrapper for Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.ITestVaultResource. */ class ITestVaultResource extends ResourceBuilderBase { ITestVaultResource(Handle handle, AspireClient client) { @@ -2669,6 +2747,96 @@ public IResource withCancellableOperation(Function operation) } +/** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService. */ +class ResourceLoggerService extends HandleWrapperBase { + ResourceLoggerService(Handle handle, AspireClient client) { + super(handle, client); + } + + /** Completes the log stream for a resource */ + public void completeLog(IResource resource) { + Map reqArgs = new HashMap<>(); + reqArgs.put("loggerService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resource", AspireClient.serializeValue(resource)); + getClient().invokeCapability("Aspire.Hosting/completeLog", reqArgs); + } + + /** Completes the log stream by resource name */ + public void completeLogByName(String resourceName) { + Map reqArgs = new HashMap<>(); + reqArgs.put("loggerService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resourceName", AspireClient.serializeValue(resourceName)); + getClient().invokeCapability("Aspire.Hosting/completeLogByName", reqArgs); + } + +} + +/** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService. */ +class ResourceNotificationService extends HandleWrapperBase { + ResourceNotificationService(Handle handle, AspireClient client) { + super(handle, client); + } + + /** Waits for a resource to reach a specified state */ + public void waitForResourceState(String resourceName, String targetState) { + Map reqArgs = new HashMap<>(); + reqArgs.put("notificationService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resourceName", AspireClient.serializeValue(resourceName)); + if (targetState != null) { + reqArgs.put("targetState", AspireClient.serializeValue(targetState)); + } + getClient().invokeCapability("Aspire.Hosting/waitForResourceState", reqArgs); + } + + /** Waits for a resource to reach one of the specified states */ + public String waitForResourceStates(String resourceName, String[] targetStates) { + Map reqArgs = new HashMap<>(); + reqArgs.put("notificationService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resourceName", AspireClient.serializeValue(resourceName)); + reqArgs.put("targetStates", AspireClient.serializeValue(targetStates)); + return (String) getClient().invokeCapability("Aspire.Hosting/waitForResourceStates", reqArgs); + } + + /** Waits for a resource to become healthy */ + public ResourceEventDto waitForResourceHealthy(String resourceName) { + Map reqArgs = new HashMap<>(); + reqArgs.put("notificationService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resourceName", AspireClient.serializeValue(resourceName)); + return (ResourceEventDto) getClient().invokeCapability("Aspire.Hosting/waitForResourceHealthy", reqArgs); + } + + /** Waits for all dependencies of a resource to be ready */ + public void waitForDependencies(IResource resource) { + Map reqArgs = new HashMap<>(); + reqArgs.put("notificationService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resource", AspireClient.serializeValue(resource)); + getClient().invokeCapability("Aspire.Hosting/waitForDependencies", reqArgs); + } + + /** Tries to get the current state of a resource */ + public ResourceEventDto tryGetResourceState(String resourceName) { + Map reqArgs = new HashMap<>(); + reqArgs.put("notificationService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resourceName", AspireClient.serializeValue(resourceName)); + return (ResourceEventDto) getClient().invokeCapability("Aspire.Hosting/tryGetResourceState", reqArgs); + } + + /** Publishes an update for a resource's state */ + public void publishResourceUpdate(IResource resource, String state, String stateStyle) { + Map reqArgs = new HashMap<>(); + reqArgs.put("notificationService", AspireClient.serializeValue(getHandle())); + reqArgs.put("resource", AspireClient.serializeValue(resource)); + if (state != null) { + reqArgs.put("state", AspireClient.serializeValue(state)); + } + if (stateStyle != null) { + reqArgs.put("stateStyle", AspireClient.serializeValue(stateStyle)); + } + getClient().invokeCapability("Aspire.Hosting/publishResourceUpdate", reqArgs); + } + +} + /** Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext. */ class ResourceUrlsCallbackContext extends HandleWrapperBase { ResourceUrlsCallbackContext(Handle handle, AspireClient client) { @@ -4049,6 +4217,16 @@ public boolean waitForReadyAsync(double timeout, CancellationToken cancellationT return (boolean) getClient().invokeCapability("Aspire.Hosting.CodeGeneration.Java.Tests/waitForReadyAsync", reqArgs); } + /** Tests multi-param callback destructuring */ + public TestRedisResource withMultiParamHandleCallback(Function callback) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + if (callback != null) { + reqArgs.put("callback", getClient().registerCallback(callback)); + } + return (TestRedisResource) getClient().invokeCapability("Aspire.Hosting.CodeGeneration.Java.Tests/withMultiParamHandleCallback", reqArgs); + } + } /** Wrapper for Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext. */ @@ -4697,29 +4875,39 @@ class UpdateCommandStateContext extends HandleWrapperBase { /** Static initializer to register handle wrappers. */ class AspireRegistrations { static { + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder", (h, c) -> new IDistributedApplicationBuilder(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplication", (h, c) -> new DistributedApplication(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference", (h, c) -> new EndpointReference(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource", (h, c) -> new IResource(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment", (h, c) -> new IResourceWithEnvironment(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", (h, c) -> new IResourceWithEndpoints(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs", (h, c) -> new IResourceWithArgs(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString", (h, c) -> new IResourceWithConnectionString(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport", (h, c) -> new IResourceWithWaitSupport(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithParent", (h, c) -> new IResourceWithParent(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource", (h, c) -> new ContainerResource(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource", (h, c) -> new ExecutableResource(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource", (h, c) -> new ProjectResource(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource", (h, c) -> new ParameterResource(h, c)); + AspireClient.registerHandleWrapper("System.ComponentModel/System.IServiceProvider", (h, c) -> new IServiceProvider(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService", (h, c) -> new ResourceNotificationService(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService", (h, c) -> new ResourceLoggerService(h, c)); + AspireClient.registerHandleWrapper("Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration", (h, c) -> new IConfiguration(h, c)); + AspireClient.registerHandleWrapper("Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment", (h, c) -> new IHostEnvironment(h, c)); + AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription", (h, c) -> new DistributedApplicationEventSubscription(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext", (h, c) -> new DistributedApplicationExecutionContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContextOptions", (h, c) -> new DistributedApplicationExecutionContextOptions(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder", (h, c) -> new IDistributedApplicationBuilder(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription", (h, c) -> new DistributedApplicationEventSubscription(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationResourceEventSubscription", (h, c) -> new DistributedApplicationResourceEventSubscription(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEvent", (h, c) -> new IDistributedApplicationEvent(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationResourceEvent", (h, c) -> new IDistributedApplicationResourceEvent(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing", (h, c) -> new IDistributedApplicationEventing(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext", (h, c) -> new CommandLineArgsCallbackContext(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference", (h, c) -> new EndpointReference(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression", (h, c) -> new EndpointReferenceExpression(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext", (h, c) -> new EnvironmentCallbackContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.UpdateCommandStateContext", (h, c) -> new UpdateCommandStateContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext", (h, c) -> new ExecuteCommandContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext", (h, c) -> new ResourceUrlsCallbackContext(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource", (h, c) -> new ContainerResource(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource", (h, c) -> new ExecutableResource(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource", (h, c) -> new ParameterResource(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString", (h, c) -> new IResourceWithConnectionString(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource", (h, c) -> new ProjectResource(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery", (h, c) -> new IResourceWithServiceDiscovery(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource", (h, c) -> new IResource(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestCallbackContext", (h, c) -> new TestCallbackContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext", (h, c) -> new TestResourceContext(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestEnvironmentContext", (h, c) -> new TestEnvironmentContext(h, c)); @@ -4728,10 +4916,6 @@ class AspireRegistrations { AspireClient.registerHandleWrapper("Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestDatabaseResource", (h, c) -> new TestDatabaseResource(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestVaultResource", (h, c) -> new TestVaultResource(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting.CodeGeneration.Java.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.ITestVaultResource", (h, c) -> new ITestVaultResource(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment", (h, c) -> new IResourceWithEnvironment(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs", (h, c) -> new IResourceWithArgs(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", (h, c) -> new IResourceWithEndpoints(h, c)); - AspireClient.registerHandleWrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport", (h, c) -> new IResourceWithWaitSupport(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Dict", (h, c) -> new AspireDict(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/List", (h, c) -> new AspireList(h, c)); AspireClient.registerHandleWrapper("Aspire.Hosting/Dict", (h, c) -> new AspireDict(h, c)); diff --git a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/AtsGeneratedAspire.verified.py b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/AtsGeneratedAspire.verified.py index 354aa95884a..0cf7e213ee0 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/AtsGeneratedAspire.verified.py +++ b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/AtsGeneratedAspire.verified.py @@ -515,6 +515,14 @@ def wait_for_ready_async(self, timeout: float, cancellation_token: CancellationT args["cancellationToken"] = cancellation_token_id return self._client.invoke_capability("Aspire.Hosting.CodeGeneration.Python.Tests/waitForReadyAsync", args) + def with_multi_param_handle_callback(self, callback: Callable[[TestCallbackContext, TestEnvironmentContext], None]) -> TestRedisResource: + """Tests multi-param callback destructuring""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + callback_id = register_callback(callback) if callback is not None else None + if callback_id is not None: + args["callback"] = callback_id + return self._client.invoke_capability("Aspire.Hosting.CodeGeneration.Python.Tests/withMultiParamHandleCallback", args) + class TestResourceContext(HandleWrapperBase): def __init__(self, handle: Handle, client: AspireClient): diff --git a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py index 2ebe21b148a..a783ab1a047 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py +++ b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py @@ -225,6 +225,12 @@ def to_dict(self) -> Dict[str, Any]: # Handle Wrappers # ============================================================================ +class CancellationToken(HandleWrapperBase): + def __init__(self, handle: Handle, client: AspireClient): + super().__init__(handle, client) + + pass + class CommandLineArgsCallbackContext(HandleWrapperBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) @@ -1169,6 +1175,23 @@ def set_cancellation_token(self, value: CancellationToken) -> ExecuteCommandCont return self._client.invoke_capability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken", args) +class IConfiguration(HandleWrapperBase): + def __init__(self, handle: Handle, client: AspireClient): + super().__init__(handle, client) + + def get_config_value(self, key: str) -> str: + """Gets a configuration value by key""" + args: Dict[str, Any] = { "configuration": serialize_value(self._handle) } + args["key"] = serialize_value(key) + return self._client.invoke_capability("Aspire.Hosting/getConfigValue", args) + + def get_connection_string(self, name: str) -> str: + """Gets a connection string by name""" + args: Dict[str, Any] = { "configuration": serialize_value(self._handle) } + args["name"] = serialize_value(name) + return self._client.invoke_capability("Aspire.Hosting/getConnectionString", args) + + class IDistributedApplicationBuilder(HandleWrapperBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) @@ -1271,13 +1294,28 @@ def __init__(self, handle: Handle, client: AspireClient): pass +class IHostEnvironment(HandleWrapperBase): + def __init__(self, handle: Handle, client: AspireClient): + super().__init__(handle, client) + + def get_environment_name(self) -> str: + """Gets the environment name""" + args: Dict[str, Any] = { "environment": serialize_value(self._handle) } + return self._client.invoke_capability("Aspire.Hosting/getEnvironmentName", args) + + def is_development(self) -> bool: + """Checks if running in Development environment""" + args: Dict[str, Any] = { "environment": serialize_value(self._handle) } + return self._client.invoke_capability("Aspire.Hosting/isDevelopment", args) + + class IResource(ResourceBuilderBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) pass -class IResourceWithArgs(HandleWrapperBase): +class IResourceWithArgs(ResourceBuilderBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) @@ -1289,13 +1327,19 @@ def __init__(self, handle: Handle, client: AspireClient): pass -class IResourceWithEndpoints(HandleWrapperBase): +class IResourceWithEndpoints(ResourceBuilderBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) pass -class IResourceWithEnvironment(HandleWrapperBase): +class IResourceWithEnvironment(ResourceBuilderBase): + def __init__(self, handle: Handle, client: AspireClient): + super().__init__(handle, client) + + pass + +class IResourceWithParent(ResourceBuilderBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) @@ -1307,12 +1351,29 @@ def __init__(self, handle: Handle, client: AspireClient): pass -class IResourceWithWaitSupport(HandleWrapperBase): +class IResourceWithWaitSupport(ResourceBuilderBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) pass +class IServiceProvider(HandleWrapperBase): + def __init__(self, handle: Handle, client: AspireClient): + super().__init__(handle, client) + + def get_service(self, type_id: str) -> Any: + """Gets a service by ATS type ID""" + args: Dict[str, Any] = { "serviceProvider": serialize_value(self._handle) } + args["typeId"] = serialize_value(type_id) + return self._client.invoke_capability("Aspire.Hosting/getService", args) + + def get_required_service(self, type_id: str) -> Any: + """Gets a required service by ATS type ID""" + args: Dict[str, Any] = { "serviceProvider": serialize_value(self._handle) } + args["typeId"] = serialize_value(type_id) + return self._client.invoke_capability("Aspire.Hosting/getRequiredService", args) + + class ITestVaultResource(ResourceBuilderBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) @@ -1848,6 +1909,76 @@ def __init__(self, handle: Handle, client: AspireClient): pass +class ResourceLoggerService(HandleWrapperBase): + def __init__(self, handle: Handle, client: AspireClient): + super().__init__(handle, client) + + def complete_log(self, resource: IResource) -> None: + """Completes the log stream for a resource""" + args: Dict[str, Any] = { "loggerService": serialize_value(self._handle) } + args["resource"] = serialize_value(resource) + self._client.invoke_capability("Aspire.Hosting/completeLog", args) + return None + + def complete_log_by_name(self, resource_name: str) -> None: + """Completes the log stream by resource name""" + args: Dict[str, Any] = { "loggerService": serialize_value(self._handle) } + args["resourceName"] = serialize_value(resource_name) + self._client.invoke_capability("Aspire.Hosting/completeLogByName", args) + return None + + +class ResourceNotificationService(HandleWrapperBase): + def __init__(self, handle: Handle, client: AspireClient): + super().__init__(handle, client) + + def wait_for_resource_state(self, resource_name: str, target_state: str | None = None) -> None: + """Waits for a resource to reach a specified state""" + args: Dict[str, Any] = { "notificationService": serialize_value(self._handle) } + args["resourceName"] = serialize_value(resource_name) + if target_state is not None: + args["targetState"] = serialize_value(target_state) + self._client.invoke_capability("Aspire.Hosting/waitForResourceState", args) + return None + + def wait_for_resource_states(self, resource_name: str, target_states: list[str]) -> str: + """Waits for a resource to reach one of the specified states""" + args: Dict[str, Any] = { "notificationService": serialize_value(self._handle) } + args["resourceName"] = serialize_value(resource_name) + args["targetStates"] = serialize_value(target_states) + return self._client.invoke_capability("Aspire.Hosting/waitForResourceStates", args) + + def wait_for_resource_healthy(self, resource_name: str) -> ResourceEventDto: + """Waits for a resource to become healthy""" + args: Dict[str, Any] = { "notificationService": serialize_value(self._handle) } + args["resourceName"] = serialize_value(resource_name) + return self._client.invoke_capability("Aspire.Hosting/waitForResourceHealthy", args) + + def wait_for_dependencies(self, resource: IResource) -> None: + """Waits for all dependencies of a resource to be ready""" + args: Dict[str, Any] = { "notificationService": serialize_value(self._handle) } + args["resource"] = serialize_value(resource) + self._client.invoke_capability("Aspire.Hosting/waitForDependencies", args) + return None + + def try_get_resource_state(self, resource_name: str) -> ResourceEventDto: + """Tries to get the current state of a resource""" + args: Dict[str, Any] = { "notificationService": serialize_value(self._handle) } + args["resourceName"] = serialize_value(resource_name) + return self._client.invoke_capability("Aspire.Hosting/tryGetResourceState", args) + + def publish_resource_update(self, resource: IResource, state: str | None = None, state_style: str | None = None) -> None: + """Publishes an update for a resource's state""" + args: Dict[str, Any] = { "notificationService": serialize_value(self._handle) } + args["resource"] = serialize_value(resource) + if state is not None: + args["state"] = serialize_value(state) + if state_style is not None: + args["stateStyle"] = serialize_value(state_style) + self._client.invoke_capability("Aspire.Hosting/publishResourceUpdate", args) + return None + + class ResourceUrlsCallbackContext(HandleWrapperBase): def __init__(self, handle: Handle, client: AspireClient): super().__init__(handle, client) @@ -2876,6 +3007,14 @@ def wait_for_ready_async(self, timeout: float, cancellation_token: CancellationT args["cancellationToken"] = cancellation_token_id return self._client.invoke_capability("Aspire.Hosting.CodeGeneration.Python.Tests/waitForReadyAsync", args) + def with_multi_param_handle_callback(self, callback: Callable[[TestCallbackContext, TestEnvironmentContext], None]) -> TestRedisResource: + """Tests multi-param callback destructuring""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + callback_id = register_callback(callback) if callback is not None else None + if callback_id is not None: + args["callback"] = callback_id + return self._client.invoke_capability("Aspire.Hosting.CodeGeneration.Python.Tests/withMultiParamHandleCallback", args) + class TestResourceContext(HandleWrapperBase): def __init__(self, handle: Handle, client: AspireClient): @@ -3348,30 +3487,41 @@ def __init__(self, handle: Handle, client: AspireClient): # Handle wrapper registrations # ============================================================================ +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder", lambda handle, client: IDistributedApplicationBuilder(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplication", lambda handle, client: DistributedApplication(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference", lambda handle, client: EndpointReference(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression", lambda handle, client: ReferenceExpression(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource", lambda handle, client: IResource(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment", lambda handle, client: IResourceWithEnvironment(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", lambda handle, client: IResourceWithEndpoints(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs", lambda handle, client: IResourceWithArgs(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString", lambda handle, client: IResourceWithConnectionString(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport", lambda handle, client: IResourceWithWaitSupport(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithParent", lambda handle, client: IResourceWithParent(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource", lambda handle, client: ContainerResource(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource", lambda handle, client: ExecutableResource(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource", lambda handle, client: ProjectResource(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource", lambda handle, client: ParameterResource(handle, client)) +register_handle_wrapper("System.ComponentModel/System.IServiceProvider", lambda handle, client: IServiceProvider(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService", lambda handle, client: ResourceNotificationService(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService", lambda handle, client: ResourceLoggerService(handle, client)) +register_handle_wrapper("Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration", lambda handle, client: IConfiguration(handle, client)) +register_handle_wrapper("Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment", lambda handle, client: IHostEnvironment(handle, client)) +register_handle_wrapper("System.Private.CoreLib/System.Threading.CancellationToken", lambda handle, client: CancellationToken(handle, client)) +register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription", lambda handle, client: DistributedApplicationEventSubscription(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext", lambda handle, client: DistributedApplicationExecutionContext(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContextOptions", lambda handle, client: DistributedApplicationExecutionContextOptions(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder", lambda handle, client: IDistributedApplicationBuilder(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationEventSubscription", lambda handle, client: DistributedApplicationEventSubscription(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Eventing.DistributedApplicationResourceEventSubscription", lambda handle, client: DistributedApplicationResourceEventSubscription(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEvent", lambda handle, client: IDistributedApplicationEvent(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationResourceEvent", lambda handle, client: IDistributedApplicationResourceEvent(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.Eventing.IDistributedApplicationEventing", lambda handle, client: IDistributedApplicationEventing(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.CommandLineArgsCallbackContext", lambda handle, client: CommandLineArgsCallbackContext(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference", lambda handle, client: EndpointReference(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReferenceExpression", lambda handle, client: EndpointReferenceExpression(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext", lambda handle, client: EnvironmentCallbackContext(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression", lambda handle, client: ReferenceExpression(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.UpdateCommandStateContext", lambda handle, client: UpdateCommandStateContext(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext", lambda handle, client: ExecuteCommandContext(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext", lambda handle, client: ResourceUrlsCallbackContext(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ContainerResource", lambda handle, client: ContainerResource(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecutableResource", lambda handle, client: ExecutableResource(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ParameterResource", lambda handle, client: ParameterResource(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithConnectionString", lambda handle, client: IResourceWithConnectionString(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.ProjectResource", lambda handle, client: ProjectResource(handle, client)) register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery", lambda handle, client: IResourceWithServiceDiscovery(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource", lambda handle, client: IResource(handle, client)) register_handle_wrapper("Aspire.Hosting.CodeGeneration.Python.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestCallbackContext", lambda handle, client: TestCallbackContext(handle, client)) register_handle_wrapper("Aspire.Hosting.CodeGeneration.Python.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext", lambda handle, client: TestResourceContext(handle, client)) register_handle_wrapper("Aspire.Hosting.CodeGeneration.Python.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestEnvironmentContext", lambda handle, client: TestEnvironmentContext(handle, client)) @@ -3380,10 +3530,6 @@ def __init__(self, handle: Handle, client: AspireClient): register_handle_wrapper("Aspire.Hosting.CodeGeneration.Python.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestDatabaseResource", lambda handle, client: TestDatabaseResource(handle, client)) register_handle_wrapper("Aspire.Hosting.CodeGeneration.Python.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestVaultResource", lambda handle, client: TestVaultResource(handle, client)) register_handle_wrapper("Aspire.Hosting.CodeGeneration.Python.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.ITestVaultResource", lambda handle, client: ITestVaultResource(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEnvironment", lambda handle, client: IResourceWithEnvironment(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithArgs", lambda handle, client: IResourceWithArgs(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", lambda handle, client: IResourceWithEndpoints(handle, client)) -register_handle_wrapper("Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport", lambda handle, client: IResourceWithWaitSupport(handle, client)) register_handle_wrapper("Aspire.Hosting/Dict", lambda handle, client: AspireDict(handle, client)) register_handle_wrapper("Aspire.Hosting/List", lambda handle, client: AspireList(handle, client)) register_handle_wrapper("Aspire.Hosting/Dict", lambda handle, client: AspireDict(handle, client)) diff --git a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/AtsGeneratedAspire.verified.rs b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/AtsGeneratedAspire.verified.rs index b17a8468856..f37f76ac6a1 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/AtsGeneratedAspire.verified.rs +++ b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/AtsGeneratedAspire.verified.rs @@ -960,6 +960,17 @@ impl TestRedisResource { let result = self.client.invoke_capability("Aspire.Hosting.CodeGeneration.Rust.Tests/waitForReadyAsync", args)?; Ok(serde_json::from_value(result)?) } + + /// Tests multi-param callback destructuring + pub fn with_multi_param_handle_callback(&self, callback: impl Fn(Vec) -> Value + Send + Sync + 'static) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let callback_id = register_callback(callback); + args.insert("callback".to_string(), Value::String(callback_id)); + let result = self.client.invoke_capability("Aspire.Hosting.CodeGeneration.Rust.Tests/withMultiParamHandleCallback", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(TestRedisResource::new(handle, self.client.clone())) + } } /// Wrapper for Aspire.Hosting.CodeGeneration.Rust.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext diff --git a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs index b2c74d37edd..883d775f201 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs +++ b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs @@ -2197,6 +2197,50 @@ impl ExecuteCommandContext { } } +/// Wrapper for Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration +pub struct IConfiguration { + handle: Handle, + client: Arc, +} + +impl HasHandle for IConfiguration { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl IConfiguration { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } + + /// Gets a configuration value by key + pub fn get_config_value(&self, key: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("configuration".to_string(), self.handle.to_json()); + args.insert("key".to_string(), serde_json::to_value(&key).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/getConfigValue", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Gets a connection string by name + pub fn get_connection_string(&self, name: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("configuration".to_string(), self.handle.to_json()); + args.insert("name".to_string(), serde_json::to_value(&name).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/getConnectionString", args)?; + Ok(serde_json::from_value(result)?) + } +} + /// Wrapper for Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder pub struct IDistributedApplicationBuilder { handle: Handle, @@ -2430,6 +2474,48 @@ impl IDistributedApplicationResourceEvent { } } +/// Wrapper for Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment +pub struct IHostEnvironment { + handle: Handle, + client: Arc, +} + +impl HasHandle for IHostEnvironment { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl IHostEnvironment { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } + + /// Gets the environment name + pub fn get_environment_name(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("environment".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/getEnvironmentName", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Checks if running in Development environment + pub fn is_development(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("environment".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/isDevelopment", args)?; + Ok(serde_json::from_value(result)?) + } +} + /// Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResource pub struct IResource { handle: Handle, @@ -2560,6 +2646,32 @@ impl IResourceWithEnvironment { } } +/// Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithParent +pub struct IResourceWithParent { + handle: Handle, + client: Arc, +} + +impl HasHandle for IResourceWithParent { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl IResourceWithParent { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } +} + /// Wrapper for Aspire.Hosting/Aspire.Hosting.IResourceWithServiceDiscovery pub struct IResourceWithServiceDiscovery { handle: Handle, @@ -2612,6 +2724,50 @@ impl IResourceWithWaitSupport { } } +/// Wrapper for System.ComponentModel/System.IServiceProvider +pub struct IServiceProvider { + handle: Handle, + client: Arc, +} + +impl HasHandle for IServiceProvider { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl IServiceProvider { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } + + /// Gets a service by ATS type ID + pub fn get_service(&self, type_id: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("serviceProvider".to_string(), self.handle.to_json()); + args.insert("typeId".to_string(), serde_json::to_value(&type_id).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/getService", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Gets a required service by ATS type ID + pub fn get_required_service(&self, type_id: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("serviceProvider".to_string(), self.handle.to_json()); + args.insert("typeId".to_string(), serde_json::to_value(&type_id).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/getRequiredService", args)?; + Ok(serde_json::from_value(result)?) + } +} + /// Wrapper for Aspire.Hosting.CodeGeneration.Rust.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.ITestVaultResource pub struct ITestVaultResource { handle: Handle, @@ -3500,6 +3656,140 @@ impl ProjectResource { } } +/// Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceLoggerService +pub struct ResourceLoggerService { + handle: Handle, + client: Arc, +} + +impl HasHandle for ResourceLoggerService { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl ResourceLoggerService { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } + + /// Completes the log stream for a resource + pub fn complete_log(&self, resource: &IResource) -> Result<(), Box> { + let mut args: HashMap = HashMap::new(); + args.insert("loggerService".to_string(), self.handle.to_json()); + args.insert("resource".to_string(), resource.handle().to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/completeLog", args)?; + Ok(()) + } + + /// Completes the log stream by resource name + pub fn complete_log_by_name(&self, resource_name: &str) -> Result<(), Box> { + let mut args: HashMap = HashMap::new(); + args.insert("loggerService".to_string(), self.handle.to_json()); + args.insert("resourceName".to_string(), serde_json::to_value(&resource_name).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/completeLogByName", args)?; + Ok(()) + } +} + +/// Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceNotificationService +pub struct ResourceNotificationService { + handle: Handle, + client: Arc, +} + +impl HasHandle for ResourceNotificationService { + fn handle(&self) -> &Handle { + &self.handle + } +} + +impl ResourceNotificationService { + pub fn new(handle: Handle, client: Arc) -> Self { + Self { handle, client } + } + + pub fn handle(&self) -> &Handle { + &self.handle + } + + pub fn client(&self) -> &Arc { + &self.client + } + + /// Waits for a resource to reach a specified state + pub fn wait_for_resource_state(&self, resource_name: &str, target_state: Option<&str>) -> Result<(), Box> { + let mut args: HashMap = HashMap::new(); + args.insert("notificationService".to_string(), self.handle.to_json()); + args.insert("resourceName".to_string(), serde_json::to_value(&resource_name).unwrap_or(Value::Null)); + if let Some(ref v) = target_state { + args.insert("targetState".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + let result = self.client.invoke_capability("Aspire.Hosting/waitForResourceState", args)?; + Ok(()) + } + + /// Waits for a resource to reach one of the specified states + pub fn wait_for_resource_states(&self, resource_name: &str, target_states: Vec) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("notificationService".to_string(), self.handle.to_json()); + args.insert("resourceName".to_string(), serde_json::to_value(&resource_name).unwrap_or(Value::Null)); + args.insert("targetStates".to_string(), serde_json::to_value(&target_states).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/waitForResourceStates", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Waits for a resource to become healthy + pub fn wait_for_resource_healthy(&self, resource_name: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("notificationService".to_string(), self.handle.to_json()); + args.insert("resourceName".to_string(), serde_json::to_value(&resource_name).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/waitForResourceHealthy", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Waits for all dependencies of a resource to be ready + pub fn wait_for_dependencies(&self, resource: &IResource) -> Result<(), Box> { + let mut args: HashMap = HashMap::new(); + args.insert("notificationService".to_string(), self.handle.to_json()); + args.insert("resource".to_string(), resource.handle().to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/waitForDependencies", args)?; + Ok(()) + } + + /// Tries to get the current state of a resource + pub fn try_get_resource_state(&self, resource_name: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("notificationService".to_string(), self.handle.to_json()); + args.insert("resourceName".to_string(), serde_json::to_value(&resource_name).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/tryGetResourceState", args)?; + Ok(serde_json::from_value(result)?) + } + + /// Publishes an update for a resource's state + pub fn publish_resource_update(&self, resource: &IResource, state: Option<&str>, state_style: Option<&str>) -> Result<(), Box> { + let mut args: HashMap = HashMap::new(); + args.insert("notificationService".to_string(), self.handle.to_json()); + args.insert("resource".to_string(), resource.handle().to_json()); + if let Some(ref v) = state { + args.insert("state".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = state_style { + args.insert("stateStyle".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + let result = self.client.invoke_capability("Aspire.Hosting/publishResourceUpdate", args)?; + Ok(()) + } +} + /// Wrapper for Aspire.Hosting/Aspire.Hosting.ApplicationModel.ResourceUrlsCallbackContext pub struct ResourceUrlsCallbackContext { handle: Handle, @@ -5195,6 +5485,17 @@ impl TestRedisResource { let result = self.client.invoke_capability("Aspire.Hosting.CodeGeneration.Rust.Tests/waitForReadyAsync", args)?; Ok(serde_json::from_value(result)?) } + + /// Tests multi-param callback destructuring + pub fn with_multi_param_handle_callback(&self, callback: impl Fn(Vec) -> Value + Send + Sync + 'static) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let callback_id = register_callback(callback); + args.insert("callback".to_string(), Value::String(callback_id)); + let result = self.client.invoke_capability("Aspire.Hosting.CodeGeneration.Rust.Tests/withMultiParamHandleCallback", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(TestRedisResource::new(handle, self.client.clone())) + } } /// Wrapper for Aspire.Hosting.CodeGeneration.Rust.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.TestTypes.TestResourceContext diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs index f746777d558..e0dd7001a6f 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs @@ -1270,6 +1270,21 @@ public void Generate_ConcreteAndInterfaceWithSameClassName_NoDuplicateClasses() Assert.Equal(1, promiseCount); } + // ===== Multi-Parameter Callback Destructuring Tests ===== + + [Fact] + public void Generate_MultiParamCallback_UsesPerPropertyTyping() + { + // Regression test: multi-parameter callbacks must type each destructured property + // individually as { p0: unknown, p1: unknown }, not { p0, p1: unknown } which + // only types the last property in TypeScript. + var code = GenerateTwoPassCode(); + + // withMultiParamHandleCallback has a 2-param callback (TestCallbackContext, TestEnvironmentContext) + // The generated destructuring should type each property: { p0: unknown, p1: unknown } + Assert.Contains("{ p0: unknown, p1: unknown }", code); + } + private static int CountOccurrences(string text, string pattern) { var count = 0; diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts index 18465056d18..a6be97c058f 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/AtsGeneratedAspire.verified.ts @@ -1236,6 +1236,29 @@ export class TestRedisResource extends ResourceBuilderBase Promise): Promise { + const callbackId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1Handle = wrapIfHandle(args.p0) as TestCallbackContextHandle; + const arg1 = new TestCallbackContext(arg1Handle, this._client); + const arg2Handle = wrapIfHandle(args.p1) as TestEnvironmentContextHandle; + const arg2 = new TestEnvironmentContext(arg2Handle, this._client); + await callback(arg1, arg2); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.CodeGeneration.TypeScript.Tests/withMultiParamHandleCallback', + rpcArgs + ); + return new TestRedisResource(result, this._client); + } + + /** Tests multi-param callback destructuring */ + withMultiParamHandleCallback(callback: (arg1: TestCallbackContext, arg2: TestEnvironmentContext) => Promise): TestRedisResourcePromise { + return new TestRedisResourcePromise(this._withMultiParamHandleCallbackInternal(callback)); + } + } /** @@ -1378,6 +1401,11 @@ export class TestRedisResourcePromise implements PromiseLike return this._promise.then(obj => obj.waitForReadyAsync(timeout, options)); } + /** Tests multi-param callback destructuring */ + withMultiParamHandleCallback(callback: (arg1: TestCallbackContext, arg2: TestEnvironmentContext) => Promise): TestRedisResourcePromise { + return new TestRedisResourcePromise(this._promise.then(obj => obj.withMultiParamHandleCallback(callback))); + } + } // ============================================================================ diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts index fa82767376d..6e081485406 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts @@ -7467,6 +7467,29 @@ export class TestRedisResource extends ResourceBuilderBase Promise): Promise { + const callbackId = registerCallback(async (argsData: unknown) => { + const args = argsData as { p0: unknown, p1: unknown }; + const arg1Handle = wrapIfHandle(args.p0) as TestCallbackContextHandle; + const arg1 = new TestCallbackContext(arg1Handle, this._client); + const arg2Handle = wrapIfHandle(args.p1) as TestEnvironmentContextHandle; + const arg2 = new TestEnvironmentContext(arg2Handle, this._client); + await callback(arg1, arg2); + }); + const rpcArgs: Record = { builder: this._handle, callback: callbackId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting.CodeGeneration.TypeScript.Tests/withMultiParamHandleCallback', + rpcArgs + ); + return new TestRedisResource(result, this._client); + } + + /** Tests multi-param callback destructuring */ + withMultiParamHandleCallback(callback: (arg1: TestCallbackContext, arg2: TestEnvironmentContext) => Promise): TestRedisResourcePromise { + return new TestRedisResourcePromise(this._withMultiParamHandleCallbackInternal(callback)); + } + } /** @@ -7804,6 +7827,11 @@ export class TestRedisResourcePromise implements PromiseLike return this._promise.then(obj => obj.waitForReadyAsync(timeout, options)); } + /** Tests multi-param callback destructuring */ + withMultiParamHandleCallback(callback: (arg1: TestCallbackContext, arg2: TestEnvironmentContext) => Promise): TestRedisResourcePromise { + return new TestRedisResourcePromise(this._promise.then(obj => obj.withMultiParamHandleCallback(callback))); + } + } // ============================================================================ diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/TestTypes/TestExtensions.cs b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/TestTypes/TestExtensions.cs index 8c1f1e68960..e6cf4e29d11 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/TestTypes/TestExtensions.cs +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/TestTypes/TestExtensions.cs @@ -635,6 +635,19 @@ public static Task WaitForReadyAsync( return Task.FromResult(true); } + // ===== Multi-Parameter Callback Tests ===== + + /// + /// Tests multi-parameter callback with handle types for destructuring codegen. + /// + [AspireExport("withMultiParamHandleCallback", Description = "Tests multi-param callback destructuring")] + public static IResourceBuilder WithMultiParamHandleCallback( + this IResourceBuilder builder, + Func callback) + { + return builder; + } + // ===== Duplicate Class Name Tests ===== /// diff --git a/tests/Aspire.Hosting.Tests/Ats/AtsCapabilityScannerTests.cs b/tests/Aspire.Hosting.Tests/Ats/AtsCapabilityScannerTests.cs index 129de89e883..6bd08d7b233 100644 --- a/tests/Aspire.Hosting.Tests/Ats/AtsCapabilityScannerTests.cs +++ b/tests/Aspire.Hosting.Tests/Ats/AtsCapabilityScannerTests.cs @@ -193,6 +193,60 @@ public void DerivePackage_NestedCapabilityId_ReturnsPackage() #endregion + #region Assembly-Level AspireExport Tests + + [Fact] + public void ScanAssembly_AssemblyLevelExport_AppearsInHandleTypes() + { + // Regression test: assembly-level [AspireExport(typeof(T))] attributes must be + // discovered and included in HandleTypes so they participate in Unknown→Handle resolution. + // The Aspire.Hosting assembly exports CancellationToken at assembly level. + var hostingAssembly = typeof(DistributedApplication).Assembly; + var result = AtsCapabilityScanner.ScanAssembly(hostingAssembly); + + // ContainerApp types are exported via assembly-level attributes in AppContainers, + // but CancellationToken is exported in Aspire.Hosting's AtsTypeMappings.cs + var cancellationTokenType = result.HandleTypes + .FirstOrDefault(t => t.AtsTypeId.Contains("CancellationToken")); + + Assert.NotNull(cancellationTokenType); + } + + #endregion + + #region Callback Parameter Type Resolution Tests + + [Fact] + public void ScanAssembly_MultiParamCallbackTypes_AreResolved() + { + // Regression test: callback parameter types must be resolved (not left as Unknown) + // when the types are exported. Previously only param.Type was resolved but not + // param.CallbackParameters[i].Type. + var testAssembly = typeof(AtsCapabilityScannerTests).Assembly; + var hostingAssembly = typeof(DistributedApplication).Assembly; + + var result = AtsCapabilityScanner.ScanAssemblies([hostingAssembly, testAssembly]); + + // Find the testMultiParamHandleCallback capability + var capability = result.Capabilities + .FirstOrDefault(c => c.CapabilityId.EndsWith("/testMultiParamHandleCallback", StringComparison.Ordinal)); + + Assert.NotNull(capability); + + var callbackParam = Assert.Single(capability.Parameters, p => p.IsCallback); + Assert.NotNull(callbackParam.CallbackParameters); + Assert.Equal(2, callbackParam.CallbackParameters.Count); + + // Both callback parameter types should be resolved to Handle (not Unknown) + foreach (var cbParam in callbackParam.CallbackParameters) + { + Assert.NotNull(cbParam.Type); + Assert.NotEqual(AtsTypeCategory.Unknown, cbParam.Type.Category); + } + } + + #endregion + #region Test Types private sealed class TestResource : Resource @@ -217,6 +271,15 @@ public static IEnumerable TestEnumerableReturn(IDistributedApplicationBu _ = builder; return []; } + + [AspireExport("testMultiParamHandleCallback")] + public static IResourceBuilder TestMultiParamHandleCallback( + IResourceBuilder builder, + Func callback) + { + _ = callback; + return builder; + } } #endregion