string Name { get; }
Source
Gets the stable event name.
Describes a registered AppSurface product-event contract.
string Name { get; }
Source
Gets the stable event name.
AppSurfaceProductEventLifecycle Lifecycle { get; }
Source
Gets the current lifecycle state.
string Purpose { get; }
Source
Gets the decision the event is meant to support.
string Owner { get; }
Source
Gets the owning AppSurface component or package.
string RetentionExpectation { get; }
Source
Gets the expected retention class for downstream sinks.
IReadOnlyList<AppSurfaceProductEventPropertyContract> Properties { get; }
Source
Gets the allowed property schema.
IReadOnlyList<string> ForbiddenExamples { get; }
Source
Gets examples of values or property shapes that must not be captured.
Normalizes and sanitizes product-event metadata before registry validation or sink emission.
This internal helper separates constructor-time normalization, which trims and rejects empty required values, from emission-time sanitization, which may return null for unsafe optional envelope values. Methods that validate required input throw for empty or duplicate values; methods named Sanitize* return null when values are too long, contain unsafe characters, or look like tokens, cookies, secrets, connection strings, bearer headers, stack traces, full URLs, query strings, or fragments.
string RequireIdentifier(string value, string parameterName)
Source
Trims and requires a non-empty identifier-like value.
This method is for event and property names. It does not apply the stricter route or envelope sanitizers. Callers receive an ArgumentException for null, empty, or whitespace-only input.
string RequireText(string value, string parameterName)
Source
Trims and requires non-empty text.
Use this for registry descriptions, owners, examples, and allowed values. It throws for null, empty, or whitespace-only values, and otherwise returns the trimmed text unchanged.
string? NormalizeOptionalText(string? value)
Source
Trims optional text and normalizes null, empty, or whitespace-only values to null.
IReadOnlyDictionary<string, string> NormalizeProperties(IReadOnlyDictionary<string, string>? properties, string parameterName)
Source
Copies property keys and values into an ordinal, read-only dictionary.
Property names are required and trimmed through RequireIdentifier. Property values are trimmed, with null or whitespace-only values normalized to an empty string so optional string properties can still be represented. Later duplicate keys replace earlier values according to dictionary assignment semantics.
IReadOnlyList<AppSurfaceProductEventPropertyContract> NormalizeContracts(IEnumerable<AppSurfaceProductEventPropertyContract> contracts, string parameterName)
Source
Copies and validates a required property-contract sequence.
The returned list is a read-only wrapper over a private copy. Empty sequences and duplicate property names throw because every event contract must publish an explicit schema.
IReadOnlyList<string> NormalizeTextList(IEnumerable<string> values, string parameterName)
Source
Copies and validates a required list of non-empty text values.
Values are trimmed with RequireText and returned as a read-only wrapper over a private copy. Duplicate handling is left to callers because some lists may allow duplicates while others do not.
IReadOnlyList<string> NormalizeOptionalTextList(IEnumerable<string>? values, string parameterName)
Source
Copies and validates an optional list of unique non-empty text values.
Null input becomes an empty read-only list. Non-null input is trimmed, duplicate values throw, and the returned value should be treated as immutable by registry contracts.
string? SanitizeEnvelopeIdentifier(string? value)
Source
Filters optional actor, session, or correlation identifiers for sink-safe emission.
Safe identifiers are short ASCII tokens containing only letters, digits, -, _, ., :, or |. Values with whitespace, PII-shaped punctuation, bearer headers, tokens, cookies, secrets, connection strings, or stack-trace text are dropped by returning null.
string? SanitizeRoute(string? value)
Source
Filters optional route templates or surface names for sink-safe emission.
Routes may contain path separators and route-template braces, but full URLs, protocol-relative URLs, query strings, fragments outside route tokens, unsafe characters, high-risk value shapes, and overlong routes are dropped. Do not pass concrete route values that contain user, tenant, object, or channel identifiers.
bool ContainsForbiddenValueShape(string value)
Source
Returns whether a value looks like a secret, credential, connection string, bearer header, or stack trace.
bool ContainsQueryOrFragment(string value)
Source
Returns whether a route-like value contains a query string or fragment outside a route token.
Default product-intelligence dispatcher registered by AppSurface.
ValueTask CaptureAsync(AppSurfaceProductEvent productEvent, CancellationToken cancellationToken = default)
Source
Invalid events are discarded silently after AppSurfaceProductEventRegistry.Validate(AppSurfaceProductEvent). Experimental contracts are also ignored unless AppSurfaceProductIntelligenceOptions.ExperimentalEventsEnabled enables the whole experimental surface or AppSurfaceProductIntelligenceOptions.IsExperimentalEventEnabled(string) enables that specific event name through the per-event allowlist. Registered sinks run sequentially, and non-cancellation sink failures are swallowed so product-intelligence capture cannot break request paths. Callers should treat this method as best-effort delivery and should not rely on it to surface sink errors or guarantee that a downstream analytics provider accepted the event.
Describes one allowed property on a registered AppSurface product event.
string Name { get; }
Source
Gets the stable property name accepted in event payloads.
string Description { get; }
Source
Gets the human-readable purpose and expected value shape.
AppSurfaceProductEventSensitivity Sensitivity { get; }
Source
Gets the privacy sensitivity classification.
AppSurfaceProductEventCardinality Cardinality { get; }
Source
Gets the expected cardinality budget.
bool Required { get; }
Source
Gets a value indicating whether capture should drop the event when the property is absent.
IReadOnlyList<string> AllowedValues { get; }
Source
Gets the optional bounded set of allowed values for low-cardinality dimensions.
int MaxLength { get; }
Source
Gets the maximum allowed emitted value length.
Describes the expected cardinality budget for a product-event property.
The numeric values are explicit because this public enum may be serialized, persisted, or used in generated registry documentation. New values should be appended without changing the values documented here.
Configures AppSurface product-intelligence capture.
AppSurfaceProductIntelligenceOptions EnableExperimentalEvents()
Source
Allows experimental event contracts to be emitted.
The same options instance for fluent configuration.
This method is a one-way toggle on the same options instance: it sets ExperimentalEventsEnabled to true and does not provide a matching disable operation. Avoid sharing and mutating one options instance across unrelated components when that one-way behavior would be surprising.
AppSurfaceProductIntelligenceOptions EnableExperimentalEvents(params string[] eventNames)
Source
Allows selected experimental event contracts to be emitted.
eventNamesRegistered experimental event names to allow.The same options instance for fluent configuration.
Use this when a host or package wants a narrow product-intelligence surface without enabling every experimental AppSurface event. Blank names are rejected during configuration so typos do not silently widen or narrow capture. Registered sinks still receive only events that pass AppSurfaceProductEventRegistry.Validate(AppSurfaceProductEvent).
bool IsExperimentalEventEnabled(string eventName)
Source
Determines whether one experimental event name is allowed by this options instance.
eventNameThe experimental event name to test.true when all experimental events or the specific event name are enabled.
bool ExperimentalEventsEnabled { get; set; }
Source
Gets a value indicating whether experimental event contracts may be emitted.
The default is false. Keep this disabled for hosts that have not yet chosen product-event sinks, retention rules, and access controls. Enable it only during explicit dogfooding or host configuration where experimental AppSurface event contracts are expected to flow.
IReadOnlySet<string> EnabledExperimentalEventNames { get; }
Source
Gets experimental event names that are enabled without enabling every experimental contract.
This allowlist lets package integrations enable one product area, such as AppSurface Docs search-quality metrics, without turning on unrelated experimental dogfood events. Values are event names from AppSurfaceProductEventRegistry. The returned set is a copy so callers cannot mutate options state after configuration.
Registers the surface-neutral AppSurface product-intelligence composition boundary.
The module registers a passive dispatcher and options type. It does not configure PostHog, OpenTelemetry, cookies, JavaScript autocapture, persistence, retention, access control, dashboards, or session replay.
void ConfigureServices(StartupContext context, IServiceCollection services)
Source
Registers product-intelligence services for the current startup graph.
contextStartup context for the current AppSurface composition pass.servicesService collection that receives product-intelligence services.void RegisterDependentModules(ModuleDependencyBuilder builder)
Source
Registers dependent modules required by product intelligence.
builderThe module dependency builder for the current startup graph.Captures AppSurface-owned product-intelligence events.
Implementations validate against AppSurfaceProductEventRegistry before forwarding events to any host-owned transport. The interface is intentionally vendor-neutral and must not require PostHog, OpenTelemetry, or a browser analytics SDK.
ValueTask CaptureAsync(AppSurfaceProductEvent productEvent, CancellationToken cancellationToken = default)
Source
Captures a product-intelligence event if the registry and options allow it.
productEventProduct event to capture.cancellationTokenCancellation token for the capture path.A task that completes when registered sinks have accepted or skipped the event.
Receives validated AppSurface product-intelligence events for host-owned transport.
Sinks are optional. AppSurface does not configure persistence, retention, access control, dashboards, or vendor libraries. Register a sink only after deciding which host-owned analytics system should receive the sanitized event stream.
ValueTask CaptureAsync(AppSurfaceProductEvent productEvent, CancellationToken cancellationToken = default)
Source
Receives one sanitized product-intelligence event.
productEventSanitized product event with only registry-allowed properties and safe envelope fields.cancellationTokenCancellation token for the capture path.A task that completes when the sink has accepted the event.
Registers AppSurface product-intelligence services.
IServiceCollection AddAppSurfaceProductIntelligence(this IServiceCollection services, Action<AppSurfaceProductIntelligenceOptions>? configure = null)
Source
Adds the AppSurface product-intelligence dispatcher and options.
servicesService collection to configure.configureOptional options callback. Call AppSurfaceProductIntelligenceOptions.EnableExperimentalEvents() to emit dogfood events.The original service collection.
Hosts own IAppSurfaceProductIntelligenceSink registration, transport, retention, and vendor setup. This extension registers the default dispatcher with TryAddScoped, so repeated calls do not replace an existing IAppSurfaceProductIntelligence registration. Repeated calls can still accumulate options configuration delegates, so callers should avoid duplicate configure actions. Call AppSurfaceProductIntelligenceOptions.EnableExperimentalEvents() only when experimental dogfood events should be emitted to host-owned sinks.
Classifies the privacy sensitivity of a product-event property.
The numeric values are explicit because this public enum may be serialized, persisted, or used in generated registry documentation. New values should be appended without changing the values documented here.
Describes one AppSurface product-intelligence event instance.
AppSurface product events are semantic product signals, not logs, traces, request captures, or vendor-specific analytics payloads. Hosts own transport, retention, access control, and downstream product analytics setup.
AppSurfaceProductEvent WithSanitizedEnvelope(IReadOnlyDictionary<string, string> properties)
Source
Creates a new event with sanitized envelope metadata and replacement properties.
propertiesReplacement event properties that have already passed registry sanitization.A new event with sanitized envelope metadata.
This internal API does not mutate the current event. The supplied properties replace the original property set, while ActorId, SessionId, and CorrelationId are filtered through AppSurfaceProductEventMetadata.SanitizeEnvelopeIdentifier and Route is filtered through AppSurfaceProductEventMetadata.SanitizeRoute. Sanitization may drop optional envelope values by returning null when they are too long, contain unsafe characters, or look like secrets, PII, bearer headers, query strings, fragments, full URLs, or concrete high-cardinality route values. Callers must supply an already-sanitized property dictionary and must not assume original envelope values survive this step.
string Name { get; }
Source
Gets the registered event name.
DateTimeOffset Timestamp { get; }
Source
Gets the timestamp supplied by the caller.
IReadOnlyDictionary<string, string> Properties { get; }
Source
Gets property values copied with ordinal keys.
string? ActorId { get; }
Source
Gets the optional host-normalized actor identifier.
string? SessionId { get; }
Source
Gets the optional host-normalized session identifier.
string? CorrelationId { get; }
Source
Gets the optional low-cardinality correlation identifier for trace or request joins.
string? Route { get; }
Source
Gets the optional route template or surface name.
Describes the lifecycle promise attached to an AppSurface product event contract.
The numeric values are explicit because this public enum may be serialized, persisted, or used in generated registry documentation. New values should be appended without changing the values documented here.
Source-of-truth registry for AppSurface product-intelligence event contracts.
AppSurfaceProductEventContract? Find(string name)
Source
Finds a registered contract by event name.
nameEvent name to look up.The matching contract, or null when no contract is registered.
AppSurfaceProductEventValidationResult Validate(AppSurfaceProductEvent productEvent)
Source
Validates and sanitizes a product event against the typed registry.
productEventEvent instance to validate.Validation result with safe diagnostics and sanitized properties.
IReadOnlyList<AppSurfaceProductEventContract> All { get; }
Source
Gets every registered AppSurface product event contract.
IReadOnlySet<string> ForbiddenProperties { get; }
Source
Gets globally forbidden property names that are always dropped from emitted payloads.
Describes registry validation and sanitization for one product event.
AppSurfaceProductEventContract? Contract { get; }
Source
Gets the matched event contract, or null when the event is not registered.
bool IsValid { get; }
Source
Gets a value indicating whether the event may be emitted after sanitization.
IReadOnlyDictionary<string, string> SanitizedProperties { get; }
Source
Gets properties that may be emitted to a sink.
IReadOnlyList<string> RejectedProperties { get; }
Source
Gets property names rejected during validation.
IReadOnlyList<string> Diagnostics { get; }
Source
Gets safe diagnostics that describe rejected schema decisions without echoing rejected values.