Skip to content

Commit 2f5bded

Browse files
authored
Document .NET public API surface (#211)
* fix: document public API surface * fix: clarify nullable feature flag docs * docs: clarify group collection changeset * test: cover group collection key semantics
1 parent 479f5ca commit 2f5bded

45 files changed

Lines changed: 444 additions & 54 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/gentle-ducks-share.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"PostHog": patch
3+
"PostHog.AspNetCore": patch
4+
"PostHog.AI": patch
5+
---
6+
7+
Document public APIs and make `GroupCollection.TryAdd(Group)` store entries by group type instead of group key, matching the collection's one-group-per-type behavior.

src/PostHog.AI/PostHogAIContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ private PostHogAIContext(
9797
/// <param name="groups">Optional groups to associate with events.</param>
9898
/// <param name="privacyMode">Optional flag to enable/disable privacy mode.</param>
9999
/// <returns>An <see cref="IDisposable"/> that ends the scope when disposed.</returns>
100+
/// <remarks>
101+
/// Context is stored in <see cref="AsyncLocal{T}"/> and flows with asynchronous execution. Nested scopes inherit
102+
/// parent values for any null arguments. Parent and child property/group dictionaries are merged, with child values
103+
/// overriding parent values for duplicate keys. Disposing the returned object restores the previous context.
104+
/// </remarks>
100105
public static IDisposable BeginScope(
101106
string? distinctId = null,
102107
string? traceId = null,

src/PostHog.AI/PostHogAIExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ public static IHttpClientBuilder AddPostHogOpenAIHandler(this IHttpClientBuilder
3333

3434
/// <summary>
3535
/// Adds an <see cref="OpenAIClient"/> that intercepts requests and sends events to PostHog.
36-
/// Note: This will override the <see cref="OpenAIClientOptions.Transport"/> property to use the PostHog handler.
36+
/// Note: This sets the <c>OpenAIClientOptions.Transport</c> property to use the PostHog handler and throws if a custom transport is already configured.
3737
/// </summary>
3838
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
3939
/// <param name="apiKey">The OpenAI API key.</param>
4040
/// <param name="configureOptions">Optional action to configure <see cref="OpenAIClientOptions"/>.</param>
4141
/// <returns>The <see cref="IHttpClientBuilder"/> for the underlying HttpClient, allowing further customization (e.g. resilience).</returns>
42+
/// <exception cref="ArgumentException">Thrown when <paramref name="apiKey"/> is null, empty, or whitespace.</exception>
43+
/// <exception cref="InvalidOperationException">Thrown when PostHog services are not registered or when <paramref name="configureOptions"/> sets a custom transport.</exception>
4244
public static IHttpClientBuilder AddPostHogOpenAIClient(
4345
this IServiceCollection services,
4446
string apiKey,

src/PostHog.AI/PostHogOpenAIHandler.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,18 @@ public class PostHogOpenAIHandler : DelegatingHandler
1515
private readonly IPostHogClient _postHogClient;
1616
private readonly ILogger<PostHogOpenAIHandler> _logger;
1717

18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="PostHogOpenAIHandler"/> class.
20+
/// </summary>
21+
/// <param name="postHogClient">The PostHog client used to capture AI observability events.</param>
22+
/// <param name="logger">The logger used to report capture failures.</param>
1823
public PostHogOpenAIHandler(IPostHogClient postHogClient, ILogger<PostHogOpenAIHandler> logger)
1924
{
2025
_postHogClient = postHogClient ?? throw new ArgumentNullException(nameof(postHogClient));
2126
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
2227
}
2328

29+
/// <inheritdoc />
2430
protected override async Task<HttpResponseMessage> SendAsync(
2531
HttpRequestMessage request,
2632
CancellationToken cancellationToken

src/PostHog.AspNetCore/Cache/HttpContextFeatureFlagCache.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ namespace PostHog.Cache;
1111
/// An implementation of <see cref="IFeatureFlagCache"/> that uses the current <see cref="HttpContext"/> to cache
1212
/// feature flags. If the <see cref="HttpContext"/> is not available, then the feature flags are not cached.
1313
/// </summary>
14+
/// <param name="httpContextAccessor">Accessor for the current <see cref="HttpContext"/>.</param>
15+
/// <param name="logger">Logger used to report cache hits, misses, and cache access failures.</param>
1416
public class HttpContextFeatureFlagCache(
1517
IHttpContextAccessor httpContextAccessor,
1618
ILogger<HttpContextFeatureFlagCache> logger) : IFeatureFlagCache
1719
{
1820
/// <summary>
1921
/// Constructs a new instance of <see cref="HttpContextFeatureFlagCache"/> without a logger.
2022
/// </summary>
21-
/// <param name="httpContextAccessor"></param>
23+
/// <param name="httpContextAccessor">Accessor for the current <see cref="HttpContext"/>.</param>
2224
public HttpContextFeatureFlagCache(IHttpContextAccessor httpContextAccessor)
2325
: this(httpContextAccessor, NullLogger<HttpContextFeatureFlagCache>.Instance)
2426
{

src/PostHog.AspNetCore/Config/IPostHogAspNetCoreConfigurationBuilder.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ namespace PostHog.Config;
77
/// </summary>
88
public interface IPostHogAspNetCoreConfigurationBuilder : IPostHogConfigurationBuilder
99
{
10+
/// <summary>
11+
/// Gets the ASP.NET Core application configuration.
12+
/// </summary>
1013
public IConfiguration Configuration { get; }
1114
}

src/PostHog.AspNetCore/Config/PostHogConfigurationBuilderExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static IPostHogConfigurationBuilder UseAspNetCore(this IPostHogConfigurat
3838
/// person properties and groups when evaluating feature flags. There's a base implementation of
3939
/// <see cref="PostHogFeatureFlagContextProvider"/> you can override.
4040
/// </remarks>
41+
/// <typeparam name="TContextProvider">The context provider type used to supply feature flag evaluation context.</typeparam>
4142
/// <param name="builder">The <see cref="IPostHogConfigurationBuilder"/>.</param>
4243
/// <returns>The passed in <see cref="IPostHogConfigurationBuilder"/>.</returns>
4344
public static IPostHogConfigurationBuilder UseFeatureManagement<TContextProvider>(this IPostHogConfigurationBuilder builder)
@@ -54,6 +55,7 @@ public static IPostHogConfigurationBuilder UseFeatureManagement<TContextProvider
5455
/// <see cref="PostHogFeatureFlagContextProvider"/> you can override.
5556
/// </remarks>
5657
/// <param name="builder">The <see cref="IPostHogConfigurationBuilder"/>.</param>
58+
/// <typeparam name="TContextProvider">The context provider type used to supply feature flag evaluation context.</typeparam>
5759
/// <param name="configure">
5860
/// Action used to configure the <see cref="IFeatureManagementBuilder"/>. Use this to provide a custom
5961
/// <see cref="ITargetingContextAccessor"/>.

src/PostHog.AspNetCore/FeatureManagement/PostHogFeatureDefinitionProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace PostHog.FeatureManagement;
99
/// <param name="posthog">The <see cref="IPostHogClient"/> used to evaluate feature flags.</param>
1010
public class PostHogFeatureDefinitionProvider(IPostHogClient posthog) : IFeatureDefinitionProvider
1111
{
12+
/// <inheritdoc />
1213
public async Task<FeatureDefinition?> GetFeatureDefinitionAsync(string featureName)
1314
{
1415
await foreach (var feature in GetAllFeatureDefinitionsAsync())
@@ -21,6 +22,7 @@ public class PostHogFeatureDefinitionProvider(IPostHogClient posthog) : IFeature
2122
return null;
2223
}
2324

25+
/// <inheritdoc />
2426
public async IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync()
2527
{
2628
var localEvaluator = await posthog.GetLocalEvaluatorAsync(CancellationToken.None);

src/PostHog.AspNetCore/FeatureManagement/PostHogFeatureFilter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace PostHog.FeatureManagement;
77
/// PostHog <see cref="IFeatureFilter"/> that uses PostHog's API to check if a feature is enabled for the current user.
88
/// </summary>
99
/// <param name="variantFeatureManager">The <see cref="IVariantFeatureManager"/> we'll use to evaluate the flag.</param>
10+
/// <param name="logger">The logger used to report registration problems.</param>
1011
[FilterAlias("PostHog")]
1112
public class PostHogFeatureFilter(IVariantFeatureManager variantFeatureManager, ILogger<PostHogFeatureFilter> logger)
1213
: IFeatureFilter

src/PostHog.AspNetCore/FeatureManagement/PostHogVariantFeatureManager.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ namespace PostHog.FeatureManagement;
1111
/// </summary>
1212
/// <param name="posthog">The <see cref="IPostHogClient"/> used to evaluate feature flags.</param>
1313
/// <param name="targetingContextAccessor">The <see cref="ITargetingContextAccessor" /> used to evaluate feature flags.</param>
14+
/// <param name="logger">The logger used to report registration problems.</param>
1415
public class PostHogVariantFeatureManager(
1516
IPostHogClient posthog,
1617
ITargetingContextAccessor targetingContextAccessor,
1718
ILogger<PostHogVariantFeatureManager> logger)
1819
: IVariantFeatureManager
1920
{
21+
/// <inheritdoc />
2022
public async IAsyncEnumerable<string> GetFeatureNamesAsync(
2123
[EnumeratorCancellation] CancellationToken cancellationToken = new())
2224
{
@@ -31,13 +33,15 @@ public async IAsyncEnumerable<string> GetFeatureNamesAsync(
3133
}
3234
}
3335

36+
/// <inheritdoc />
3437
public async ValueTask<bool> IsEnabledAsync(string feature, CancellationToken cancellationToken = new())
3538
{
3639
var targetingContext = await targetingContextAccessor.GetContextAsync();
3740

3841
return await IsEnabledAsync<TargetingContext>(feature, targetingContext, cancellationToken);
3942
}
4043

44+
/// <inheritdoc />
4145
public async ValueTask<bool> IsEnabledAsync<TContext>(
4246
string feature,
4347
TContext context,
@@ -47,12 +51,14 @@ public async ValueTask<bool> IsEnabledAsync<TContext>(
4751
return flag is { IsEnabled: true };
4852
}
4953

54+
/// <inheritdoc />
5055
public async ValueTask<Variant> GetVariantAsync(string feature, CancellationToken cancellationToken = new())
5156
{
5257
var targetingContext = await targetingContextAccessor.GetContextAsync();
5358
return await GetVariantAsync(feature, targetingContext, cancellationToken);
5459
}
5560

61+
/// <inheritdoc />
5662
public async ValueTask<Variant> GetVariantAsync(
5763
string feature,
5864
ITargetingContext? context,

0 commit comments

Comments
 (0)