File: Ats\CoreExports.cs
Web Access
Project: src\src\Aspire.Hosting\Aspire.Hosting.csproj (Aspire.Hosting)
// 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.ApplicationModel;
 
namespace Aspire.Hosting.Ats;
 
/// <summary>
/// Core ATS (Aspire Type System) exports for polyglot app host support.
/// </summary>
/// <remarks>
/// <para>
/// This class defines the foundational capabilities that enable non-.NET languages (TypeScript, Python, etc.)
/// to build Aspire distributed applications. These exports form the stable API surface for polyglot app hosts.
/// </para>
/// <para>
/// <strong>Design Principles:</strong>
/// <list type="bullet">
///   <item><description>Capabilities are the contract - not CLR method signatures</description></item>
///   <item><description>Handles replace direct object references - guest code never sees .NET types</description></item>
///   <item><description>Capability IDs use format {Package}/{Method}</description></item>
///   <item><description>.NET implementation details are hidden behind a stable polyglot surface</description></item>
/// </list>
/// </para>
/// <para>
/// <strong>Capability Naming Convention:</strong> <c>{Package}/{operation}</c>
/// </para>
/// <para>
/// <strong>Usage from TypeScript:</strong>
/// <code>
/// // Create builder and add resources
/// const builder = await client.invoke("Aspire.Hosting/createBuilder", {});
/// const redis = await client.invoke("Aspire.Hosting/addContainer", { builder, name: "cache", image: "redis:latest" });
/// await client.invoke("Aspire.Hosting/withEnvironment", { resource: redis, name: "REDIS_MODE", value: "standalone" });
///
/// // Build and run
/// const app = await client.invoke("Aspire.Hosting/build", { builder });
/// await client.invoke("Aspire.Hosting/run", { app });
/// </code>
/// </para>
/// </remarks>
internal static class CoreExports
{
    #region Application Lifecycle
 
    // Note: createBuilder is now on DistributedApplication.CreateBuilder
    // Note: build is now on IDistributedApplicationBuilder.Build via [AspireExport("build")]
    // Note: run is now on DistributedApplication.RunAsync via [AspireExport("run")]
    // Note: ExecutionContext, Configuration, Environment, and AppHostDirectory are accessed via property getters
    // on IDistributedApplicationBuilder which has [AspireExport(ExposeProperties = true)].
 
    // Note: getEndpoint is now on ResourceBuilderExtensions.GetEndpoint
    // Note: withReference is now on ResourceBuilderExtensions.WithReference
 
    #endregion
 
    #region Container Configuration
 
    /// <summary>
    /// Adds a volume to a container resource.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Volumes persist data across container restarts. Named volumes are managed
    /// by Docker/Podman and stored in a system-managed location.
    /// </para>
    /// <para>
    /// <strong>Why this wrapper exists:</strong> The original <c>ContainerResourceBuilderExtensions.WithVolume</c>
    /// has parameter order <c>(name?, target, isReadOnly)</c> where the optional <c>name</c> comes first.
    /// This wrapper reorders parameters to <c>(target, name?, isReadOnly)</c> so the required <c>target</c>
    /// parameter comes first, providing a better API for polyglot consumers.
    /// </para>
    /// </remarks>
    /// <param name="resource">The container resource builder handle.</param>
    /// <param name="target">The mount path inside the container.</param>
    /// <param name="name">The volume name. If null, an anonymous volume is created.</param>
    /// <param name="isReadOnly">Whether the volume is read-only.</param>
    /// <returns>The same resource builder handle for chaining.</returns>
    [AspireExport("withVolume", Description = "Adds a volume")]
    public static IResourceBuilder<ContainerResource> WithVolume(
        IResourceBuilder<ContainerResource> resource,
        string target,
        string? name = null,
        bool isReadOnly = false)
    {
        return resource.WithVolume(name, target, isReadOnly);
    }
 
    #endregion
 
    #region Resource Information
 
    /// <summary>
    /// Gets the name of the resource from a builder.
    /// </summary>
    /// <remarks>
    /// <strong>Why this wrapper exists:</strong> This capability accesses a nested property
    /// (<c>resource.Resource.Name</c>) which requires a wrapper method. There is no single
    /// .NET method that returns just the resource name that could be annotated directly.
    /// </remarks>
    /// <param name="resource">The resource builder handle.</param>
    /// <returns>The resource name.</returns>
    [AspireExport("getResourceName", Description = "Gets the resource name")]
    public static string GetResourceName(IResourceBuilder<IResource> resource)
    {
        return resource.Resource.Name;
    }
 
    #endregion
 
    #region Parameters
 
    // Note: withDescription is now on ParameterResourceBuilderExtensions.WithDescription
 
    #endregion
}