Add TS configured publication document handles

This commit is contained in:
Meta Vens 2026-06-27 17:07:04 +01:00
commit 47941b5fb3
3 changed files with 169 additions and 3 deletions

View file

@ -321,6 +321,10 @@ The same typed-definition overload is available for
`CultMesh.documentFromStore(...)` and `CultMesh.documentFromSingleFile(...)`, so
local schema publications can be read as typed reactive documents without
manually pulling records, decoding MessagePack, or parsing the payload.
When the caller wants source selection to be configuration, use
`CultMesh.documentFromPublication(...)` with a `single-file`, `store`, or
`peer-snapshot` source; it returns the same typed handle while hiding whether
sync came from local persistence or a remote CultNet snapshot.
## Streaming Mode

View file

@ -67,6 +67,21 @@ export interface CultMeshRouteRecord {
readonly description: string;
}
export type CultMeshDocumentPublicationSource =
| {
readonly kind: "single-file";
readonly path: string;
}
| {
readonly kind: "store";
readonly store: CacheBackingStore;
}
| {
readonly kind: "peer-snapshot";
readonly peer: CultNetPeer | (() => CultNetPeer | Promise<CultNetPeer>);
readonly endpoint?: string;
};
export interface CultMeshAuthorityClaim {
readonly role: string;
readonly shardId?: string;
@ -2129,6 +2144,102 @@ export function cultMeshDocumentFromPeerSnapshot(
);
}
export function cultMeshDocumentFromPublication(
source: CultMeshDocumentPublicationSource,
schemaId: string,
recordKey: string,
options?: {
documentId?: string;
routeHint?: CultMeshRouteHint;
sourceId?: string;
timeoutMs?: number;
pollMs?: number;
messageIdPrefix?: string;
},
): CultMeshDocumentHandle<unknown>;
export function cultMeshDocumentFromPublication<TDefinition extends AnyCultCacheDocumentDefinition>(
source: CultMeshDocumentPublicationSource,
definition: TDefinition,
recordKey: string,
options?: {
documentId?: string;
routeHint?: CultMeshRouteHint;
sourceId?: string;
timeoutMs?: number;
pollMs?: number;
messageIdPrefix?: string;
},
): CultMeshDocumentHandle<CultCacheDocumentValue<TDefinition>>;
export function cultMeshDocumentFromPublication(
source: CultMeshDocumentPublicationSource,
schemaOrDefinition: string | AnyCultCacheDocumentDefinition,
recordKey: string,
options: {
documentId?: string;
routeHint?: CultMeshRouteHint;
sourceId?: string;
timeoutMs?: number;
pollMs?: number;
messageIdPrefix?: string;
} = {},
): CultMeshDocumentHandle<unknown> {
if (!source) {
throw new Error("CultMesh publication source is required.");
}
requireNonEmpty(recordKey, "recordKey");
switch (source.kind) {
case "single-file":
return typeof schemaOrDefinition === "string"
? cultMeshDocumentFromSingleFile(source.path, schemaOrDefinition, {
documentId: options.documentId ?? recordKey,
routeHint: options.routeHint,
sourceId: options.sourceId ?? recordKey,
pollMs: options.pollMs,
})
: cultMeshDocumentFromSingleFile(source.path, schemaOrDefinition, {
documentId: options.documentId ?? recordKey,
routeHint: options.routeHint,
sourceId: options.sourceId ?? recordKey,
pollMs: options.pollMs,
});
case "store":
return typeof schemaOrDefinition === "string"
? cultMeshDocumentFromStore(source.store, schemaOrDefinition, {
documentId: options.documentId ?? recordKey,
routeHint: options.routeHint,
sourceId: options.sourceId ?? recordKey,
pollMs: options.pollMs,
})
: cultMeshDocumentFromStore(source.store, schemaOrDefinition, {
documentId: options.documentId ?? recordKey,
routeHint: options.routeHint,
sourceId: options.sourceId ?? recordKey,
pollMs: options.pollMs,
});
case "peer-snapshot":
return typeof schemaOrDefinition === "string"
? cultMeshDocumentFromPeerSnapshot(source.peer, schemaOrDefinition, recordKey, {
documentId: options.documentId ?? recordKey,
routeHint: options.routeHint ?? cultMeshRouteHint("network", source.endpoint ?? "CultNet snapshot"),
sourceId: options.sourceId ?? recordKey,
timeoutMs: options.timeoutMs,
pollMs: options.pollMs,
messageIdPrefix: options.messageIdPrefix,
})
: cultMeshDocumentFromPeerSnapshot(source.peer, schemaOrDefinition, recordKey, {
documentId: options.documentId ?? recordKey,
routeHint: options.routeHint ?? cultMeshRouteHint("network", source.endpoint ?? "CultNet snapshot"),
sourceId: options.sourceId ?? recordKey,
timeoutMs: options.timeoutMs,
pollMs: options.pollMs,
messageIdPrefix: options.messageIdPrefix,
});
default:
throw new Error(`Unsupported CultMesh publication source kind '${(source as { kind?: string }).kind}'.`);
}
}
export function cultMeshGlobalDocumentFromCache<TDefinition extends AnyCultCacheDocumentDefinition>(
cache: CultCache,
definition: TDefinition,
@ -3925,6 +4036,50 @@ export class CultMesh {
: cultMeshDocumentFromPeerSnapshot(peer, schemaOrDefinition, recordKey, options);
}
public static documentFromPublication(
source: CultMeshDocumentPublicationSource,
schemaId: string,
recordKey: string,
options?: {
documentId?: string;
routeHint?: CultMeshRouteHint;
sourceId?: string;
timeoutMs?: number;
pollMs?: number;
messageIdPrefix?: string;
},
): CultMeshDocumentHandle<unknown>;
public static documentFromPublication<TDefinition extends AnyCultCacheDocumentDefinition>(
source: CultMeshDocumentPublicationSource,
definition: TDefinition,
recordKey: string,
options?: {
documentId?: string;
routeHint?: CultMeshRouteHint;
sourceId?: string;
timeoutMs?: number;
pollMs?: number;
messageIdPrefix?: string;
},
): CultMeshDocumentHandle<CultCacheDocumentValue<TDefinition>>;
public static documentFromPublication(
source: CultMeshDocumentPublicationSource,
schemaOrDefinition: string | AnyCultCacheDocumentDefinition,
recordKey: string,
options: {
documentId?: string;
routeHint?: CultMeshRouteHint;
sourceId?: string;
timeoutMs?: number;
pollMs?: number;
messageIdPrefix?: string;
} = {},
): CultMeshDocumentHandle<unknown> {
return typeof schemaOrDefinition === "string"
? cultMeshDocumentFromPublication(source, schemaOrDefinition, recordKey, options)
: cultMeshDocumentFromPublication(source, schemaOrDefinition, recordKey, options);
}
public static globalDocumentFromCache<TDefinition extends AnyCultCacheDocumentDefinition>(
cache: CultCache,
definition: TDefinition,

View file

@ -196,7 +196,10 @@ test("CultMesh TS document handles read schema publications from single-file sto
});
await node.flush();
const document = CultMesh.documentFromSingleFile(filePath, noteDocument, {
const document = CultMesh.documentFromPublication({
kind: "single-file",
path: filePath,
}, noteDocument, "note:publication", {
documentId: "daemon:cultmesh.note.latest",
sourceId: "daemon:cultmesh.note.latest.v0",
pollMs: 50,
@ -1949,8 +1952,12 @@ test("CultMesh TS reads remote RUDP snapshots through document handles", async (
},
);
const document = CultMesh.documentFromPeerSnapshot(
peer,
const document = CultMesh.documentFromPublication(
{
kind: "peer-snapshot",
peer,
endpoint: `rudp://127.0.0.1:${server.bind.port}`,
},
noteDocument,
"note:remote",
{