Add CultMesh typed document handles
This commit is contained in:
parent
57c9125e10
commit
c911eb561d
4 changed files with 4832 additions and 0 deletions
|
|
@ -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>
|
||||
|
|
|
|||
2775
src/GameCult.Mesh/CultMeshPrimitives.cs
Normal file
2775
src/GameCult.Mesh/CultMeshPrimitives.cs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
Loading…
Reference in a new issue