Add CultMesh typed document handles

This commit is contained in:
Meta Vens 2026-06-27 14:30:59 +01:00
commit c911eb561d
4 changed files with 4832 additions and 0 deletions

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
@ -297,6 +298,796 @@ namespace GameCult.Mesh
return new CultMeshStreamCatalog();
}
/// <summary>
/// Creates a managed Verse context for generated domain sugar.
/// </summary>
public static CultMeshVerse Verse(
string verseId,
string runtimeId,
CultMeshRouteHint? routeHint = null,
IEnumerable<CultMeshAuthorityClaim>? claims = null)
{
return new CultMeshVerse(new CultMeshVerseContext(verseId, runtimeId, routeHint, claims));
}
/// <summary>
/// Creates a managed Verse context for generated domain sugar.
/// </summary>
public static Task<CultMeshVerse> ConnectVerseAsync(
string verseId,
string runtimeId,
CultMeshRouteHint? routeHint = null,
IEnumerable<CultMeshAuthorityClaim>? claims = null)
{
return Task.FromResult(Verse(verseId, runtimeId, routeHint, claims));
}
/// <summary>
/// Starts a fluent typed operation context for one runtime.
/// </summary>
public static CultMeshOperationContextBuilder OperationContextFor(string runtimeId)
{
return new CultMeshOperationContextBuilder(runtimeId);
}
/// <summary>
/// Starts a fluent typed query context for one runtime.
/// </summary>
public static CultMeshQueryContextBuilder QueryContextFor(string runtimeId)
{
return new CultMeshQueryContextBuilder(runtimeId);
}
/// <summary>
/// Binds a typed operation handle to a Verse context.
/// </summary>
public static CultMeshBoundOperationHandle<TRequest, TResponse> BindOperation<TRequest, TResponse>(
CultMeshVerseContext context,
CultMeshOperationHandle<TRequest, TResponse> operation)
{
return new CultMeshBoundOperationHandle<TRequest, TResponse>(context, operation);
}
/// <summary>
/// Binds a typed operation handle to a Verse.
/// </summary>
public static CultMeshBoundOperationHandle<TRequest, TResponse> BindOperation<TRequest, TResponse>(
CultMeshVerse verse,
CultMeshOperationHandle<TRequest, TResponse> operation)
{
if (verse == null) throw new ArgumentNullException(nameof(verse));
return BindOperation(verse.Context, operation);
}
/// <summary>
/// Binds a typed query surface to a Verse context.
/// </summary>
public static CultMeshBoundQuerySurface<TParameters, TResult> BindQuery<TParameters, TResult>(
CultMeshVerseContext context,
CultMeshQuerySurface<TParameters, TResult> query)
{
return new CultMeshBoundQuerySurface<TParameters, TResult>(context, query);
}
/// <summary>
/// Binds a typed query surface to a Verse.
/// </summary>
public static CultMeshBoundQuerySurface<TParameters, TResult> BindQuery<TParameters, TResult>(
CultMeshVerse verse,
CultMeshQuerySurface<TParameters, TResult> query)
{
if (verse == null) throw new ArgumentNullException(nameof(verse));
return BindQuery(verse.Context, query);
}
/// <summary>
/// Binds a typed live feed to a Verse context.
/// </summary>
public static CultMeshBoundLiveFeed<TParameters, TResult> BindLiveFeed<TParameters, TResult>(
CultMeshVerseContext context,
CultMeshLiveFeed<TParameters, TResult> feed)
{
return new CultMeshBoundLiveFeed<TParameters, TResult>(context, feed);
}
/// <summary>
/// Binds a typed live feed to a Verse.
/// </summary>
public static CultMeshBoundLiveFeed<TParameters, TResult> BindLiveFeed<TParameters, TResult>(
CultMeshVerse verse,
CultMeshLiveFeed<TParameters, TResult> feed)
{
if (verse == null) throw new ArgumentNullException(nameof(verse));
return BindLiveFeed(verse.Context, feed);
}
/// <summary>
/// Binds a typed document live feed to a Verse context.
/// </summary>
public static CultMeshDocumentHandle<TDocument> BindDocument<TDocument>(
CultMeshVerseContext context,
CultMeshLiveFeed<CultMeshDocumentQueryParameters, TDocument> feed)
where TDocument : class
{
return new CultMeshDocumentHandle<TDocument>(BindLiveFeed(context, feed));
}
/// <summary>
/// Binds a typed document live feed to a Verse.
/// </summary>
public static CultMeshDocumentHandle<TDocument> BindDocument<TDocument>(
CultMeshVerse verse,
CultMeshLiveFeed<CultMeshDocumentQueryParameters, TDocument> feed)
where TDocument : class
{
if (verse == null) throw new ArgumentNullException(nameof(verse));
return BindDocument(verse.Context, feed);
}
/// <summary>
/// Binds a typed state pointer to a Verse context.
/// </summary>
public static CultMeshBoundStatePointer<TValue> BindStatePointer<TValue>(
CultMeshVerseContext context,
CultMeshStatePointer<TValue> pointer)
{
return new CultMeshBoundStatePointer<TValue>(context, pointer);
}
/// <summary>
/// Binds a typed state pointer to a Verse.
/// </summary>
public static CultMeshBoundStatePointer<TValue> BindStatePointer<TValue>(
CultMeshVerse verse,
CultMeshStatePointer<TValue> pointer)
{
if (verse == null) throw new ArgumentNullException(nameof(verse));
return BindStatePointer(verse.Context, pointer);
}
/// <summary>
/// Binds a mutable typed state pointer to a Verse context.
/// </summary>
public static CultMeshBoundMutableStatePointer<TValue> BindMutableStatePointer<TValue>(
CultMeshVerseContext context,
CultMeshMutableStatePointer<TValue> pointer)
{
return new CultMeshBoundMutableStatePointer<TValue>(context, pointer);
}
/// <summary>
/// Binds a mutable typed state pointer to a Verse.
/// </summary>
public static CultMeshBoundMutableStatePointer<TValue> BindMutableStatePointer<TValue>(
CultMeshVerse verse,
CultMeshMutableStatePointer<TValue> pointer)
{
if (verse == null) throw new ArgumentNullException(nameof(verse));
return BindMutableStatePointer(verse.Context, pointer);
}
/// <summary>
/// Creates a typed state pointer to Verse state.
/// </summary>
public static CultMeshStatePointer<TValue> StatePointer<TValue>(
string pointerId,
Func<Task<TValue?>> resolve,
Func<R3.Observable<TValue>> watch,
CultMeshRouteHint? routeHint = null,
IEnumerable<CultMeshProjectionSource>? sources = null)
{
return new CultMeshStatePointer<TValue>(
pointerId,
resolve,
watch,
routeHint,
sources);
}
/// <summary>
/// Creates a typed state pointer to Verse state that can resolve through a query context.
/// </summary>
public static CultMeshStatePointer<TValue> StatePointer<TValue>(
string pointerId,
Func<CultMeshQueryContext, Task<TValue?>> resolve,
Func<CultMeshQueryContext, R3.Observable<TValue>> watch,
CultMeshRouteHint? routeHint = null,
IEnumerable<CultMeshProjectionSource>? sources = null)
{
return new CultMeshStatePointer<TValue>(
pointerId,
resolve,
watch,
routeHint,
sources);
}
/// <summary>
/// Creates a mutable typed state pointer to Verse state.
/// </summary>
public static CultMeshMutableStatePointer<TValue> MutableStatePointer<TValue>(
string pointerId,
Func<Task<TValue?>> resolve,
Func<R3.Observable<TValue>> watch,
Func<TValue, Task> replace,
CultMeshRouteHint? routeHint = null,
IEnumerable<CultMeshProjectionSource>? sources = null)
{
return new CultMeshMutableStatePointer<TValue>(
pointerId,
resolve,
watch,
replace,
routeHint,
sources);
}
/// <summary>
/// Creates a mutable typed state pointer to Verse state that can operate through a query context.
/// </summary>
public static CultMeshMutableStatePointer<TValue> MutableStatePointer<TValue>(
string pointerId,
Func<CultMeshQueryContext, Task<TValue?>> resolve,
Func<CultMeshQueryContext, R3.Observable<TValue>> watch,
Func<CultMeshQueryContext, TValue, Task> replace,
CultMeshRouteHint? routeHint = null,
IEnumerable<CultMeshProjectionSource>? sources = null)
{
return new CultMeshMutableStatePointer<TValue>(
pointerId,
resolve,
watch,
replace,
routeHint,
sources);
}
/// <summary>
/// Creates a typed projection source descriptor.
/// </summary>
public static CultMeshProjectionSource ProjectionSource(
string sourceId,
string? schemaId = null,
string? description = null)
{
return new CultMeshProjectionSource(sourceId, schemaId, description);
}
/// <summary>
/// Creates a named state-reference resolver for portable UI/tool surfaces.
/// </summary>
public static CultMeshStateRefResolver StateRefResolver(
string resolverId,
Func<string, string?> resolve,
IEnumerable<CultMeshProjectionSource>? sources = null,
CultMeshRouteHint? routeHint = null)
{
if (resolve == null) throw new ArgumentNullException(nameof(resolve));
return new CultMeshStateRefResolver(
resolverId,
(stateRef, _context) => resolve(stateRef),
sources,
routeHint);
}
/// <summary>
/// Creates a named state-reference resolver for portable UI/tool surfaces.
/// </summary>
public static CultMeshStateRefResolver StateRefResolver(
string resolverId,
Func<string, CultMeshQueryContext, string?> resolve,
IEnumerable<CultMeshProjectionSource>? sources = null,
CultMeshRouteHint? routeHint = null)
{
return new CultMeshStateRefResolver(resolverId, resolve, sources, routeHint);
}
/// <summary>
/// Describes a state-reference resolver for catalogs and tools.
/// </summary>
public static CultMeshStateRefResolverDiagnostic DescribeStateRefResolver(
CultMeshStateRefResolver resolver)
{
if (resolver == null) throw new ArgumentNullException(nameof(resolver));
return new CultMeshStateRefResolverDiagnostic(
resolver.ResolverId,
resolver.RouteHint,
resolver.Sources);
}
/// <summary>
/// Creates a UI/tool binding descriptor from a component property to a typed state pointer.
/// </summary>
public static CultMeshStateBindingDescriptor StateBinding<TValue>(
string targetProp,
CultMeshStatePointer<TValue> pointer)
{
return CultMeshStateBindingDescriptor.FromPointer(targetProp, pointer);
}
/// <summary>
/// Creates a UI/tool binding descriptor from a component property to a mutable typed state pointer.
/// </summary>
public static CultMeshStateBindingDescriptor StateBinding<TValue>(
string targetProp,
CultMeshMutableStatePointer<TValue> pointer)
{
if (pointer == null) throw new ArgumentNullException(nameof(pointer));
return CultMeshStateBindingDescriptor.FromPointer(targetProp, pointer.AsStatePointer());
}
/// <summary>
/// Creates a UI/tool binding descriptor from a component property to a state pointer id.
/// </summary>
public static CultMeshStateBindingDescriptor StateBinding(
string targetProp,
string pointerId,
string? sourceId = null,
string? schemaId = null,
CultMeshRouteHint? routeHint = null)
{
return new CultMeshStateBindingDescriptor(targetProp, pointerId, sourceId, schemaId, routeHint);
}
/// <summary>
/// Creates transport-friendly fields from a state binding descriptor.
/// </summary>
public static CultMeshStateBindingRecord StateBindingRecord(CultMeshStateBindingDescriptor? binding)
{
return CultMeshStateBindingRecord.FromBinding(binding);
}
/// <summary>
/// Creates transport-friendly state binding fields directly.
/// </summary>
public static CultMeshStateBindingRecord StateBindingRecord(
string? targetProp,
string? pointerId,
string? sourceId = null,
string? schemaId = null,
string? routeKind = null,
string? routeDescription = null)
{
return new CultMeshStateBindingRecord(
targetProp,
pointerId,
sourceId,
schemaId,
routeKind,
routeDescription);
}
/// <summary>
/// Creates a UI/tool command binding descriptor from a typed operation handle.
/// </summary>
public static CultMeshOperationBindingDescriptor OperationBinding<TRequest, TResponse>(
CultMeshOperationHandle<TRequest, TResponse> operation,
string? label = null,
string? schemaId = null,
CultMeshRouteHint? routeHint = null)
{
return CultMeshOperationBindingDescriptor.FromOperation(operation, label, schemaId, routeHint);
}
/// <summary>
/// Creates a UI/tool command binding descriptor from a typed operation id.
/// </summary>
public static CultMeshOperationBindingDescriptor OperationBinding(
string operationId,
string? label = null,
string? schemaId = null,
CultMeshRouteHint? routeHint = null)
{
return new CultMeshOperationBindingDescriptor(operationId, label, schemaId, routeHint);
}
/// <summary>
/// Creates transport-friendly fields from an operation binding descriptor.
/// </summary>
public static CultMeshOperationBindingRecord OperationBindingRecord(
CultMeshOperationBindingDescriptor? binding)
{
return CultMeshOperationBindingRecord.FromBinding(binding);
}
/// <summary>
/// Creates transport-friendly operation binding fields directly.
/// </summary>
public static CultMeshOperationBindingRecord OperationBindingRecord(
string? operationId,
string? label = null,
string? schemaId = null,
string? routeKind = null,
string? routeDescription = null)
{
return new CultMeshOperationBindingRecord(
operationId,
label,
schemaId,
routeKind,
routeDescription);
}
/// <summary>
/// Creates a concrete invocation descriptor from an advertised operation binding.
/// </summary>
public static CultMeshOperationInvocationDescriptor OperationInvocation(
CultMeshOperationBindingDescriptor binding,
string? idempotencyKey = null)
{
return CultMeshOperationInvocationDescriptor.FromBinding(binding, idempotencyKey);
}
/// <summary>
/// Creates a concrete invocation descriptor from a typed operation handle.
/// </summary>
public static CultMeshOperationInvocationDescriptor OperationInvocation<TRequest, TResponse>(
CultMeshOperationHandle<TRequest, TResponse> operation,
string? schemaId = null,
CultMeshRouteHint? routeHint = null,
string? idempotencyKey = null)
{
return CultMeshOperationInvocationDescriptor.FromOperation(
operation,
schemaId,
routeHint,
idempotencyKey);
}
/// <summary>
/// Creates a concrete invocation descriptor from a typed operation id.
/// </summary>
public static CultMeshOperationInvocationDescriptor OperationInvocation(
string operationId,
string? schemaId = null,
CultMeshRouteHint? routeHint = null,
string? idempotencyKey = null)
{
return new CultMeshOperationInvocationDescriptor(operationId, schemaId, routeHint, idempotencyKey);
}
/// <summary>
/// Creates transport-friendly fields from a route hint.
/// </summary>
public static CultMeshRouteRecord RouteRecord(CultMeshRouteHint? routeHint)
{
return CultMeshRouteRecord.FromRoute(routeHint);
}
/// <summary>
/// Creates transport-friendly route fields directly.
/// </summary>
public static CultMeshRouteRecord RouteRecord(string? kind, string? description = null)
{
return new CultMeshRouteRecord(kind, description);
}
/// <summary>
/// Creates transport-friendly fields from a typed operation invocation.
/// </summary>
public static CultMeshOperationInvocationRecord OperationInvocationRecord(
CultMeshOperationInvocationDescriptor? invocation,
string? fallbackOperationId = null,
string? fallbackSchemaId = null,
CultMeshRouteHint? fallbackRouteHint = null,
string? fallbackIdempotencyKey = null)
{
return CultMeshOperationInvocationRecord.FromInvocation(
invocation,
fallbackOperationId,
fallbackSchemaId,
fallbackRouteHint,
fallbackIdempotencyKey);
}
/// <summary>
/// Creates transport-friendly operation invocation fields directly.
/// </summary>
public static CultMeshOperationInvocationRecord OperationInvocationRecord(
string? operationId,
string? schemaId = null,
string? routeKind = null,
string? routeDescription = null,
string? idempotencyKey = null)
{
return new CultMeshOperationInvocationRecord(
operationId,
schemaId,
routeKind,
routeDescription,
idempotencyKey);
}
/// <summary>
/// Creates an empty shared operation payload.
/// </summary>
public static CultMeshOperationPayload OperationPayload()
{
return CultMeshOperationPayload.Empty;
}
/// <summary>
/// Creates a shared operation payload from string-compatible fields.
/// </summary>
public static CultMeshOperationPayload OperationPayload(
IEnumerable<KeyValuePair<string, string>>? fields)
{
return CultMeshOperationPayload.FromStrings(fields);
}
/// <summary>
/// Creates a shared operation payload from key/value pairs.
/// </summary>
public static CultMeshOperationPayload OperationPayload(params (string Key, string Value)[] fields)
{
var pairs = fields?.Select(field => new KeyValuePair<string, string>(field.Key, field.Value));
return CultMeshOperationPayload.FromStrings(pairs);
}
/// <summary>
/// Creates a reusable projection recipe over typed source state.
/// </summary>
public static CultMeshProjectionRecipe<TParameters, TResult> ProjectionRecipe<TParameters, TResult>(
string projectionId,
IEnumerable<CultMeshProjectionSource> sources,
Func<TParameters, CultMeshQueryContext, Task<TResult>> project,
CultMeshRouteHint? routeHint = null,
Func<TParameters, CultMeshQueryContext, R3.Observable<TResult>>? watch = null)
{
return new CultMeshProjectionRecipe<TParameters, TResult>(
projectionId,
sources,
project,
routeHint,
watch);
}
/// <summary>
/// Creates a typed live feed surface for coherent client snapshots.
/// </summary>
public static CultMeshLiveFeed<TParameters, TResult> LiveFeed<TParameters, TResult>(
string feedId,
Func<TParameters, CultMeshQueryContext, Task<TResult>> snapshot,
Func<TParameters, CultMeshQueryContext, R3.Observable<TResult>>? watch = null,
IEnumerable<CultMeshProjectionSource>? sources = null,
CultMeshRouteHint? routeHint = null)
{
return new CultMeshLiveFeed<TParameters, TResult>(
feedId,
snapshot,
watch,
sources,
routeHint);
}
/// <summary>
/// Creates a typed document handle from snapshot/watch delegates and binds it to a Verse context.
/// </summary>
public static CultMeshDocumentHandle<TDocument> Document<TDocument>(
string documentId,
CultMeshVerseContext context,
Func<CultMeshQueryContext, Task<TDocument>> latest,
Func<CultMeshQueryContext, R3.Observable<TDocument>> watch,
IEnumerable<CultMeshProjectionSource>? sources = null,
CultMeshRouteHint? routeHint = null)
where TDocument : class
{
if (latest == null) throw new ArgumentNullException(nameof(latest));
if (watch == null) throw new ArgumentNullException(nameof(watch));
var feed = LiveFeed<CultMeshDocumentQueryParameters, TDocument>(
documentId,
(_parameters, queryContext) => latest(queryContext),
(_parameters, queryContext) => watch(queryContext),
sources,
routeHint);
return BindDocument(context, feed);
}
/// <summary>
/// Creates a typed document handle from snapshot/watch delegates and binds it to a Verse.
/// </summary>
public static CultMeshDocumentHandle<TDocument> Document<TDocument>(
string documentId,
CultMeshVerse verse,
Func<CultMeshQueryContext, Task<TDocument>> latest,
Func<CultMeshQueryContext, R3.Observable<TDocument>> watch,
IEnumerable<CultMeshProjectionSource>? sources = null,
CultMeshRouteHint? routeHint = null)
where TDocument : class
{
if (verse == null) throw new ArgumentNullException(nameof(verse));
return Document(documentId, verse.Context, latest, watch, sources, routeHint);
}
/// <summary>
/// Describes a typed live feed surface for tooling, UI, and diagnostics.
/// </summary>
public static CultMeshLiveFeedDiagnostic DescribeLiveFeed<TParameters, TResult>(
CultMeshLiveFeed<TParameters, TResult> feed)
{
if (feed == null) throw new ArgumentNullException(nameof(feed));
return new CultMeshLiveFeedDiagnostic(feed.FeedId, feed.RouteHint, feed.Sources);
}
/// <summary>
/// Describes a typed query surface for tooling, UI, and diagnostics.
/// </summary>
public static CultMeshQuerySurfaceDiagnostic DescribeQuerySurface<TParameters, TResult>(
CultMeshQuerySurface<TParameters, TResult> query)
{
if (query == null) throw new ArgumentNullException(nameof(query));
return new CultMeshQuerySurfaceDiagnostic(query.QueryId, query.RouteHint, query.Sources);
}
/// <summary>
/// Describes a typed operation handle for tooling, UI, and diagnostics.
/// </summary>
public static CultMeshOperationHandleDiagnostic DescribeOperationHandle<TRequest, TResponse>(
CultMeshOperationHandle<TRequest, TResponse> operation)
{
if (operation == null) throw new ArgumentNullException(nameof(operation));
return new CultMeshOperationHandleDiagnostic(operation.OperationId);
}
/// <summary>
/// Describes a typed state pointer for tooling, UI, and diagnostics.
/// </summary>
public static CultMeshStatePointerDiagnostic DescribeStatePointer<TValue>(
CultMeshStatePointer<TValue> pointer)
{
if (pointer == null) throw new ArgumentNullException(nameof(pointer));
return new CultMeshStatePointerDiagnostic(pointer.PointerId, pointer.RouteHint, pointer.Sources);
}
/// <summary>
/// Describes a mutable typed state pointer for tooling, UI, and diagnostics.
/// </summary>
public static CultMeshStatePointerDiagnostic DescribeStatePointer<TValue>(
CultMeshMutableStatePointer<TValue> pointer)
{
if (pointer == null) throw new ArgumentNullException(nameof(pointer));
return new CultMeshStatePointerDiagnostic(pointer.PointerId, pointer.RouteHint, pointer.Sources);
}
/// <summary>
/// Describes a native slice view for tooling, UI, and diagnostics.
/// </summary>
public static CultMeshNativeSliceViewDiagnostic DescribeNativeSliceView(
CultMeshNativeSliceViewDescriptor view)
{
return new CultMeshNativeSliceViewDiagnostic(view);
}
/// <summary>
/// Describes a typed projection recipe for tooling, UI, and diagnostics.
/// </summary>
public static CultMeshProjectionRecipeDiagnostic DescribeProjectionRecipe<TParameters, TResult>(
CultMeshProjectionRecipe<TParameters, TResult> recipe)
{
if (recipe == null) throw new ArgumentNullException(nameof(recipe));
return new CultMeshProjectionRecipeDiagnostic(recipe.ProjectionId, recipe.RouteHint, recipe.Sources);
}
/// <summary>
/// Describes a typed query surface as one entry in a surface catalog.
/// </summary>
public static CultMeshSurfaceDiagnostic DescribeSurface<TParameters, TResult>(
CultMeshQuerySurface<TParameters, TResult> query)
{
if (query == null) throw new ArgumentNullException(nameof(query));
return new CultMeshSurfaceDiagnostic(CultMeshSurfaceKind.Query, query.QueryId, query.RouteHint, query.Sources);
}
/// <summary>
/// Describes a typed operation handle as one entry in a surface catalog.
/// </summary>
public static CultMeshSurfaceDiagnostic DescribeSurface<TRequest, TResponse>(
CultMeshOperationHandle<TRequest, TResponse> operation)
{
if (operation == null) throw new ArgumentNullException(nameof(operation));
return new CultMeshSurfaceDiagnostic(CultMeshSurfaceKind.Operation, operation.OperationId);
}
/// <summary>
/// Describes a typed projection recipe as one entry in a surface catalog.
/// </summary>
public static CultMeshSurfaceDiagnostic DescribeSurface<TParameters, TResult>(
CultMeshProjectionRecipe<TParameters, TResult> recipe)
{
if (recipe == null) throw new ArgumentNullException(nameof(recipe));
return new CultMeshSurfaceDiagnostic(CultMeshSurfaceKind.ProjectionRecipe, recipe.ProjectionId, recipe.RouteHint, recipe.Sources);
}
/// <summary>
/// Describes a typed live feed as one entry in a surface catalog.
/// </summary>
public static CultMeshSurfaceDiagnostic DescribeSurface<TParameters, TResult>(
CultMeshLiveFeed<TParameters, TResult> feed)
{
if (feed == null) throw new ArgumentNullException(nameof(feed));
return new CultMeshSurfaceDiagnostic(CultMeshSurfaceKind.LiveFeed, feed.FeedId, feed.RouteHint, feed.Sources);
}
/// <summary>
/// Describes a typed state pointer as one entry in a surface catalog.
/// </summary>
public static CultMeshSurfaceDiagnostic DescribeSurface<TValue>(
CultMeshStatePointer<TValue> pointer)
{
if (pointer == null) throw new ArgumentNullException(nameof(pointer));
return new CultMeshSurfaceDiagnostic(
CultMeshSurfaceKind.StatePointer,
pointer.PointerId,
pointer.RouteHint,
pointer.Sources);
}
/// <summary>
/// Describes a mutable typed state pointer as one entry in a surface catalog.
/// </summary>
public static CultMeshSurfaceDiagnostic DescribeSurface<TValue>(
CultMeshMutableStatePointer<TValue> pointer)
{
if (pointer == null) throw new ArgumentNullException(nameof(pointer));
return new CultMeshSurfaceDiagnostic(
CultMeshSurfaceKind.StatePointer,
pointer.PointerId,
pointer.RouteHint,
pointer.Sources);
}
/// <summary>
/// Describes a native slice view as one entry in a surface catalog.
/// </summary>
public static CultMeshSurfaceDiagnostic DescribeSurface(
CultMeshNativeSliceViewDescriptor view)
{
if (view == null) throw new ArgumentNullException(nameof(view));
return new CultMeshSurfaceDiagnostic(CultMeshSurfaceKind.NativeSliceView, view.ViewId, view.Route);
}
/// <summary>
/// Creates a typed surface catalog diagnostic for tooling, UI, and generated bindings.
/// </summary>
public static CultMeshSurfaceCatalogDiagnostic DescribeSurfaceCatalog(
string catalogId,
IEnumerable<CultMeshSurfaceDiagnostic> surfaces)
{
return new CultMeshSurfaceCatalogDiagnostic(catalogId, surfaces);
}
/// <summary>
/// Creates a kind-indexed surface catalog diagnostic for generated bindings, UI, and tools.
/// </summary>
public static CultMeshSurfaceCatalogIndexDiagnostic DescribeSurfaceCatalogIndex(
CultMeshSurfaceCatalogDiagnostic catalog)
{
if (catalog == null) throw new ArgumentNullException(nameof(catalog));
return catalog.IndexByKind();
}
/// <summary>
/// Creates a timer-backed query watcher for runtimes that do not yet have native reactive transport.
/// </summary>
public static Func<TParameters, CultMeshQueryContext, R3.Observable<TResult>> PollingQueryWatcher<TParameters, TResult>(
Func<TParameters, CultMeshQueryContext, Task<TResult>> sample,
CultMeshPollingWatchOptions<TResult>? options = null)
{
if (sample == null) throw new ArgumentNullException(nameof(sample));
var resolvedOptions = options ?? new CultMeshPollingWatchOptions<TResult>();
return (parameters, context) => R3.Observable.Create<TResult>(observer =>
{
var watcher = new CultMeshPollingWatcher<TParameters, TResult>(
sample,
parameters,
context,
resolvedOptions);
var subscription = watcher.Observable.Subscribe(observer);
return new CultMeshCompositeDisposable(subscription, watcher);
});
}
/// <summary>
/// Parses a rudp://host:port endpoint into its host/port parts.
/// </summary>

File diff suppressed because it is too large Load diff

View file

@ -87,6 +87,273 @@ whether a peer card is authorized for a requested role and shard. This keeps
peer exchange separate from authority instead of letting contact gossip mutate
the world.
### Cross-Runtime Primitives
These are the first shared primitives for the cozy typed Verse surface that
projects like Aetheria should build on instead of inventing daemon-specific
adapters:
In CultMesh, a primitive can be more than a data shape. Useful state-access
patterns should graduate into shared managed affordances: typed handles,
generated binding metadata, route selection, authority context, watches,
diagnostics, and native-view descriptors that let each runtime use the same
semantic API. The domain package names the thing; CultMesh supplies the fast,
portable machinery that makes it feel native.
- `CultMeshStatePointer<T>` is a typed pointer to Verse state that UI surfaces,
tools, and clients can resolve or watch without string state-ref plumbing.
`CultMesh.StatePointer(...)` creates simple or context-aware pointers.
Pointers carry source descriptors and route hints, and
`CultMesh.DescribeStatePointer(...)` exposes that metadata for catalogs and
inspectors. Context-aware pointers can bind with `Bind(...)`,
`CultMesh.BindStatePointer(...)`, or `CultMeshVerse.BindStatePointer(...)`,
producing a Verse-bound handle that resolves and watches through the shared
Verse query context instead of forcing UI/tool code to rebuild route plumbing.
- `CultMeshMutableStatePointer<T>` extends the same state pointer shape with a
typed `ReplaceAsync(...)` operation for authoritative document handles,
editor tools, and UI surfaces that intentionally write state. It keeps the
read/watch/replace trio in CultMesh instead of letting each domain package
invent private document wrappers. `CultMesh.MutableStatePointer(...)`,
`CultMesh.BindMutableStatePointer(...)`, and
`CultMeshVerse.BindMutableStatePointer(...)` preserve the same Verse context,
route hints, source diagnostics, and state-binding metadata as read-only
pointers.
- `CultMeshStateRefResolver` is the shared bridge for UI/tool surfaces that
still receive state references from authored Eve/CultUI documents. Resolvers
are named, composable, carry source descriptors and route hints, and expose
diagnostics through `CultMesh.DescribeStateRefResolver(...)`. Legacy
`Func<string, string>` lowerers can use `AsFunc()` while generated surfaces
migrate to typed state pointers and binding descriptors.
- `CultMeshStateBindingDescriptor` and `CultMeshStateBindingRecord` are the
UI/tool state edge. Live surfaces bind a component prop to a typed state
pointer; persistence and transport boundaries use
`CultMesh.StateBindingRecord(...)` instead of local pointer-field copies or
route parsers.
- `CultMeshOperationHandle<TRequest, TResponse>` is a method-shaped operation
handle. `CultMeshOperationContext`, `CultMeshAuthorityClaim`, and
`CultMeshOperationReceipt` carry runtime identity, authority metadata,
route hints, idempotency, acceptance, and diagnostics.
`CultMesh.DescribeOperationHandle(...)` exposes the operation id for surface
catalogs and generated tooling. `Bind(...)`, `CultMesh.BindOperation(...)`,
and `CultMeshVerse.BindOperation(...)` produce Verse-bound handles so
generated domain facades can invoke without re-threading context plumbing at
every call site.
- `CultMeshOperationBindingDescriptor`, `CultMeshOperationBindingRecord`,
`CultMeshOperationInvocationDescriptor`, `CultMeshOperationInvocationRecord`,
and `CultMeshOperationPayload` are the UI/tool operation edge. Live surfaces
carry typed operation identity and scalar payload reads; persistence and
transport boundaries use `CultMesh.OperationBindingRecord(...)`,
`CultMesh.OperationInvocationRecord(...)`, and
`CultMeshOperationPayload.ToDictionary()` instead of local route parsers or
ad-hoc payload maps.
- `CultMeshQuerySurface<TParameters, TResult>` is a typed derived-state query
surface. Query execution can be local, remote, shared-memory, IPC, or
WASM-routed while preserving the same semantic API. Query surfaces can also
carry source descriptors, route hints, and reactive watches so tools and UI
runtimes can inspect what state a generated query depends on, which route it
prefers, and subscribe without inventing polling glue. Query surfaces can be
bound with `Bind(...)`, `CultMesh.BindQuery(...)`, or
`CultMeshVerse.BindQuery(...)`.
- `CultMeshLiveFeed<TParameters, TResult>` is a typed live view surface for
composed client snapshots such as an RTS viewport plus selection, health, and
authority panels. It gives clients one `snapshot(...)` / `watch(...)` handle
while preserving source descriptors and route defaults. Live feeds can be
bound with `Bind(...)`, `CultMesh.BindLiveFeed(...)`, or
`CultMeshVerse.BindLiveFeed(...)`.
- `CultMeshDocumentHandle<TDocument>` is the typed reactive document edge for
CultCache/CultNet state. It exposes document metadata, one coherent
`LatestAsync()` read, and a `Watch()` stream without forcing callers through
transport or projection layers. Same-schema CLR aliases can be requested with
`AsSchemaAlias<TAlias>()`; CultMesh verifies the shared
`[CultDocument(schemaName, schemaVersion)]` identity and uses the shared
CultCache MessagePack codec for conversion.
- `CultMeshProjectionRecipe<TParameters, TResult>` names a reusable projection
from typed source state into derived state. It records source handles,
route hints, and projection execution, and can be exposed as a typed query
surface. Reactive projection recipes preserve their watcher when exposed as
query surfaces. When a caller supplies an automatic query context, the recipe
route becomes the default; explicit caller routes still win.
- `CultMeshNativeSliceViewDescriptor` and `CultMeshNativeSliceColumn` describe
typed native views for co-located runtimes such as Unity Burst jobs, Rust
slices, or browser typed arrays. `CultMesh.DescribeNativeSliceView(...)`
exposes the full view id, schema id, row count, columns, route, native handle,
and dense stride for tools and adapters.
- `CultMeshRouteHint`, `CultMeshRouteRecord`, and `CultMeshLocalityKind` name
locality choices without forcing application code to choose transport-specific
APIs. `CultMesh.RouteRecord(...)` is the shared way to flatten and rehydrate
route kind/description fields at persisted document, UI, tool, and transport
boundaries.
These types are intentionally small handles and descriptors. Generated bindings
and runtime adapters should compose them into domain sugar such as
`verse.aetheria().entity(id).pilot().move(...)`,
`zone.objects().visibleTo(units).within(rect)`, and
`renderView.AsNativeArrays()`.
The C# helpers already support the first layer of that shape:
```csharp
var context = CultMeshOperationContext
.ForRuntime("unity-raven")
.WithClaim(new CultMeshAuthorityClaim("pilot-control", shardId: "zone:local-rts"))
.WithRoute(new CultMeshRouteHint(CultMeshLocalityKind.InProcess));
await moveOperation.InvokeAsync(moveRequest, context);
```
Generated facades should bind surfaces once to the correct Verse view:
```csharp
var queryVerse = verse.WithRoute(new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory));
var commandVerse = verse.WithRoute(new CultMeshRouteHint(CultMeshLocalityKind.Network));
var visibleObjects = queryVerse.BindQuery(objectsViewport);
var movePilot = commandVerse.BindOperation(setMoveVector);
var objects = await visibleObjects.ExecuteAsync(viewportRequest);
await movePilot.InvokeAsync(moveRequest, idempotencyKey);
```
A single typed document can be surfaced the same way:
```csharp
var cockpit = CultMesh.Document(
"aetheria.ship.cockpit.current",
verse,
context => cockpitStore.LatestAsync(context),
context => cockpitStore.Watch(context),
sources: new[]
{
CultMesh.ProjectionSource(
"pilot:cockpit",
schemaId: "gamecult.aetheria.cockpit_state.v1")
});
var current = await cockpit.LatestAsync();
using var subscription = cockpit.Watch(next => RenderCockpit(next));
var daemonAlias = cockpit.AsSchemaAlias<DaemonCockpitState>();
```
```ts
const queryVerse = verse.withRoute("shared-memory", statePath);
const commandVerse = verse
.withRoute("network", endpoint)
.withClaim("commander-control", { shardId: "aetheria.local" });
const visibleObjects = CultMesh.bindQuery(queryVerse, queries.objectsViewport);
const movePilot = CultMesh.bindOperation(commandVerse, operations.setMoveVector);
const objects = await visibleObjects.execute(viewportRequest);
await movePilot.invoke({ actorEntityKey, directionX: 1, directionY: 0 });
```
Native view descriptors can name unmanaged columns without hand-entered byte
sizes:
```csharp
var view = new CultMeshNativeSliceViewDescriptor(
"aetheria.zone.render",
"gamecult.aetheria.render_body.v1",
rowCount,
new[]
{
CultMeshNativeSliceColumn.For<CultVec2>("position"),
CultMeshNativeSliceColumn.For<CultVec2>("velocity")
},
new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory));
```
Projection recipes give local projection code a shared shape before it becomes
runtime-specific glue:
```csharp
var objectsViewport = CultMesh.ProjectionRecipe<ViewportRequest, ObjectsViewport>(
"aetheria.zone.objects.visible",
new[]
{
CultMesh.ProjectionSource("daemon:aetheria.frame.latest.v1", "gamecult.aetheria.daemon_frame.v1"),
CultMesh.ProjectionSource("daemon:aetheria.authority.policy.v1")
},
(request, context) => ProjectObjectsAsync(request, context),
new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory));
var query = objectsViewport.AsQuerySurface();
```
Calling `query.ExecuteAsync(request, "unity-raven")` inherits the recipe's
shared-memory route. Calling it with a `CultMeshQueryContext` that already names
`Network`, `Ipc`, `Wasm`, or another route uses the caller's route instead.
`query.Sources` and `query.RouteHint` preserve the recipe metadata for
diagnostics, tooling, and UI/MCP surfaces. If the projection supports reactive
execution, `query.Watch(...)` / `query.watch(...)` keeps the same projection
route resolution, so a browser map tab, Unity renderer, Eve surface, or MCP
tool can subscribe through the same typed query affordance it uses for one-shot
reads.
`CultMesh.DescribeQuerySurface(...)` and
`CultMesh.DescribeProjectionRecipe(...)` expose the same metadata in a stable
diagnostic shape for generated clients, Eve/CultUI inspectors, MCP tools, and
surface catalogs. Tooling should ask CultMesh for these descriptors instead of
copying source lists and route hints by convention.
`CultMesh.DescribeSurface(...)` and `CultMesh.DescribeSurfaceCatalog(...)`
collect query surfaces, projection recipes, live feeds, operations, state
pointers, and native views into one inspectable catalog for a runtime or
generated binding package. State pointers are advertised by pointer id; native
slice views are advertised by view id and route while the full column layout
stays in `CultMeshNativeSliceViewDescriptor`.
Catalog diagnostics support exact id lookup and kind filtering so tools can
discover, for example, every operation or native view without local scan
conventions. `CultMesh.DescribeSurfaceCatalogIndex(...)` / TS
`CultMesh.surfaceCatalogIndex(...)` promotes that grouping into a shared
diagnostic shape with `queries`, `projectionRecipes`, `liveFeeds`,
`operations`, `statePointers`, and `nativeSliceViews`, so generated bindings
and tools can ask for the semantic bucket they need without copying catalog
scan logic.
Live feeds compose several query surfaces into one client-facing snapshot
without making the UI own refresh loops:
```csharp
var viewportFeed = CultMesh.LiveFeed<ViewportRequest, RtsViewportSnapshot>(
"aetheria.rts.viewport.feed",
(request, context) => SnapshotViewportAsync(request, context),
(request, context) => WatchViewport(request, context),
new[]
{
CultMesh.ProjectionSource("daemon:aetheria.frame.latest.v1"),
CultMesh.ProjectionSource("daemon:aetheria.health.latest.v1")
},
new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory));
var feedDiagnostics = CultMesh.DescribeLiveFeed(viewportFeed);
```
When a runtime has a snapshot path before it has native reactive transport,
`CultMesh.PollingQueryWatcher(...)` provides a disposable watch adapter:
```csharp
var feed = CultMesh.LiveFeed<ViewportRequest, RtsViewportSnapshot>(
"aetheria.rts.viewport.feed",
SnapshotViewportAsync,
CultMesh.PollingQueryWatcher<ViewportRequest, RtsViewportSnapshot>(
SnapshotViewportAsync,
new CultMeshPollingWatchOptions<RtsViewportSnapshot>(
TimeSpan.FromMilliseconds(50))));
```
The polling adapter is intentionally a bridge primitive: application UI code
still receives a typed `Watch(...)` handle, and the sampling loop can later be
replaced by shared-memory, IPC, network, or WASM-native reactivity without
changing renderer call sites.
The staged roadmap for growing these handles into the cross-runtime developer
experience lives in `docs/cross-runtime-primitives-roadmap.md`. When a project
discovers a reusable state-ref, operation, query, projection, authority, watch,
surface-binding, schema-generation, routing, diagnostic, or native-slab
abstraction, it should graduate into that roadmap and then into the shared
CultMesh/CultLib layer instead of remaining a private bridge.
### RUDP Helpers
`CultMesh.ParseRudpEndpoint(...)`, `CreateRudpServer(...)`,

File diff suppressed because it is too large Load diff