Core payload modeling capabilities for the XYO Protocol 2.0 ecosystem, offering TypeScript interfaces and types for defining, validating, and manipulating payloads within the XYO blockchain network.
Additional utility types for payload manipulation, filtering, value expressions, and type transformations to enhance developer experience and type safety within the XYO Protocol 2.0 ecosystem.
Type-safe property extraction and manipulation utilities for working with payload data properties.
/**
* Type representing all property keys of a payload
*/
type PayloadProperty<T extends Payload = Payload> = keyof T;
/**
* Type representing the value of a specific payload property
*/
type PayloadValue<
T extends Payload = Payload,
Key extends PayloadProperty<T> = PayloadProperty<T>
> = T[Key];
/**
* Function type for extracting property values from payloads
*/
type PayloadValueExpression<
T extends Payload = Payload,
Key extends PayloadProperty<T> = PayloadProperty<T>,
TValue = PayloadValue<T, Key>
> = (payload: T) => TValue;Usage Examples:
import {
PayloadProperty,
PayloadValue,
PayloadValueExpression,
Payload
} from "@xyo-network/payload-model";
// Define custom payload type
interface UserPayload extends Payload {
schema: "network.example.user";
name: string;
email: string;
age: number;
preferences: {
theme: "light" | "dark";
notifications: boolean;
};
}
// Extract property types
type UserProperties = PayloadProperty<UserPayload>;
// "schema" | "name" | "email" | "age" | "preferences"
type NameValue = PayloadValue<UserPayload, "name">; // string
type PreferencesValue = PayloadValue<UserPayload, "preferences">;
// { theme: "light" | "dark"; notifications: boolean; }
// Create value expression functions
const getName: PayloadValueExpression<UserPayload, "name"> = (payload) => payload.name;
const getAge: PayloadValueExpression<UserPayload, "age"> = (payload) => payload.age;
// Generic value extractor
function createValueExtractor<T extends Payload, K extends PayloadProperty<T>>(
key: K
): PayloadValueExpression<T, K> {
return (payload) => payload[key];
}
// Use value extractors
const userPayload: UserPayload = {
schema: "network.example.user",
name: "Alice",
email: "alice@example.com",
age: 25,
preferences: {
theme: "dark",
notifications: true
}
};
const nameExtractor = createValueExtractor<UserPayload, "name">("name");
const emailExtractor = createValueExtractor<UserPayload, "email">("email");
console.log("Name:", nameExtractor(userPayload)); // "Alice"
console.log("Email:", emailExtractor(userPayload)); // "alice@example.com"
// Complex value expressions
const getDisplayName: PayloadValueExpression<UserPayload, "name", string> = (payload) => {
return `${payload.name} (${payload.age})`;
};
const getTheme: PayloadValueExpression<UserPayload, "preferences", string> = (payload) => {
return payload.preferences.theme;
};
console.log("Display:", getDisplayName(userPayload)); // "Alice (25)"
console.log("Theme:", getTheme(userPayload)); // "dark"
// Array processing with value expressions
const users: UserPayload[] = [
{ schema: "network.example.user", name: "Alice", email: "alice@example.com", age: 25, preferences: { theme: "dark", notifications: true } },
{ schema: "network.example.user", name: "Bob", email: "bob@example.com", age: 30, preferences: { theme: "light", notifications: false } }
];
const names = users.map(getName);
const ages = users.map(getAge);
const themes = users.map(getTheme);
console.log("Names:", names); // ["Alice", "Bob"]
console.log("Ages:", ages); // [25, 30]
console.log("Themes:", themes); // ["dark", "light"]Interfaces and types for filtering, organizing, and managing collections of payloads.
/**
* Filter interface for payload discovery and search operations
*/
interface PayloadFindFilter {
/** Maximum number of results to return */
limit?: number;
/** Sort order for results */
order?: 'desc' | 'asc';
/** Schema filter - single schema or array of schemas to match */
schema?: string | string[];
}
/**
* Hash map interface for efficient payload storage and lookup
*/
interface PayloadHashMap<
TPayload extends Payload = Payload,
TId extends string | number | symbol = Hash
> {
/**
* Data hash mappings - maps root hashes to data hashes
* Multiple root hashes may reference the same data hash
*/
dataHash: Record<TId, TId>;
/**
* Complete payload mappings - maps hashes to full payload objects
*/
hash: Record<TId, TPayload>;
}Usage Examples:
import {
PayloadFindFilter,
PayloadHashMap,
Payload,
Hash
} from "@xyo-network/payload-model";
// Payload filtering utilities
class PayloadFilter {
static applyFilter<T extends Payload>(
payloads: T[],
filter: PayloadFindFilter
): T[] {
let result = [...payloads];
// Schema filtering
if (filter.schema) {
const schemas = Array.isArray(filter.schema) ? filter.schema : [filter.schema];
result = result.filter(payload => schemas.includes(payload.schema));
}
// Sorting (simplified example)
if (filter.order) {
result.sort((a, b) => {
const aKey = a.schema;
const bKey = b.schema;
const comparison = aKey.localeCompare(bKey);
return filter.order === 'desc' ? -comparison : comparison;
});
}
// Limit results
if (filter.limit && filter.limit > 0) {
result = result.slice(0, filter.limit);
}
return result;
}
// Create common filters
static createSchemaFilter(schema: string | string[]): PayloadFindFilter {
return { schema };
}
static createLimitFilter(limit: number, order?: 'desc' | 'asc'): PayloadFindFilter {
return { limit, order };
}
static createCompleteFilter(
schema?: string | string[],
limit?: number,
order?: 'desc' | 'asc'
): PayloadFindFilter {
return { schema, limit, order };
}
}
// Example payloads
const payloads: Payload[] = [
{ schema: "network.example.user", name: "Alice", email: "alice@example.com" },
{ schema: "network.example.product", name: "Laptop", price: 999 },
{ schema: "network.example.user", name: "Bob", email: "bob@example.com" },
{ schema: "network.example.order", userId: "alice", productId: "laptop" },
{ schema: "network.example.user", name: "Charlie", email: "charlie@example.com" }
];
// Apply various filters
const userFilter = PayloadFilter.createSchemaFilter("network.example.user");
const limitFilter = PayloadFilter.createLimitFilter(3, "asc");
const complexFilter = PayloadFilter.createCompleteFilter(
["network.example.user", "network.example.product"],
2,
"desc"
);
const userPayloads = PayloadFilter.applyFilter(payloads, userFilter);
const limitedPayloads = PayloadFilter.applyFilter(payloads, limitFilter);
const complexResults = PayloadFilter.applyFilter(payloads, complexFilter);
console.log("Users:", userPayloads.length); // 3
console.log("Limited:", limitedPayloads.length); // 3
console.log("Complex:", complexResults.length); // 2
// Hash map utilities
class PayloadHashMapManager<T extends Payload> {
private hashMap: PayloadHashMap<T> = {
dataHash: {},
hash: {}
};
// Add payload to hash map
addPayload(payload: T, hash: string, dataHash?: string): void {
this.hashMap.hash[hash] = payload;
this.hashMap.dataHash[hash] = dataHash || hash;
}
// Get payload by hash
getPayload(hash: string): T | undefined {
return this.hashMap.hash[hash];
}
// Get all payloads with same data hash
getPayloadsByDataHash(dataHash: string): T[] {
const hashes = Object.entries(this.hashMap.dataHash)
.filter(([_, dHash]) => dHash === dataHash)
.map(([hash, _]) => hash);
return hashes
.map(hash => this.hashMap.hash[hash])
.filter((payload): payload is T => payload !== undefined);
}
// Get statistics
getStats(): {
totalPayloads: number;
uniqueDataHashes: number;
duplicateDataHashes: number;
} {
const totalPayloads = Object.keys(this.hashMap.hash).length;
const dataHashes = Object.values(this.hashMap.dataHash);
const uniqueDataHashes = new Set(dataHashes).size;
const duplicateDataHashes = dataHashes.length - uniqueDataHashes;
return {
totalPayloads,
uniqueDataHashes,
duplicateDataHashes
};
}
// Export hash map
export(): PayloadHashMap<T> {
return { ...this.hashMap };
}
}
// Use hash map manager
interface UserPayload extends Payload {
schema: "network.example.user";
name: string;
email: string;
}
const hashMapManager = new PayloadHashMapManager<UserPayload>();
const user1: UserPayload = {
schema: "network.example.user",
name: "Alice",
email: "alice@example.com"
};
const user2: UserPayload = {
schema: "network.example.user",
name: "Alice",
email: "alice@example.com"
}; // Same data, different hash
hashMapManager.addPayload(user1, "0x123...", "0xabc...");
hashMapManager.addPayload(user2, "0x456...", "0xabc..."); // Same data hash
const stats = hashMapManager.getStats();
console.log("Stats:", stats); // { totalPayloads: 2, uniqueDataHashes: 1, duplicateDataHashes: 1 }
const duplicates = hashMapManager.getPayloadsByDataHash("0xabc...");
console.log("Duplicates:", duplicates.length); // 2Types and interfaces for working with payload sets and collections of schema requirements.
/**
* PayloadSet schema constant
*/
const PayloadSetSchema = "network.xyo.payload.set" as const;
type PayloadSetSchema = typeof PayloadSetSchema;
/**
* Interface defining required and optional schema counts
*/
interface PayloadSet {
/** Optional schemas with their minimum required counts */
optional?: Record<string, number>;
/** Required schemas with their minimum required counts */
required?: Record<string, number>;
}
/**
* PayloadSet payload type combining schema requirements with payload structure
*/
type PayloadSetPayload = Payload<PayloadSet, PayloadSetSchema>;Usage Examples:
import {
PayloadSet,
PayloadSetPayload,
PayloadSetSchema,
Payload
} from "@xyo-network/payload-model";
// Define a payload set requirement
const apiPayloadSet: PayloadSetPayload = {
schema: PayloadSetSchema,
required: {
"network.example.user": 1, // At least 1 user payload required
"network.example.session": 1 // At least 1 session payload required
},
optional: {
"network.example.metadata": 2, // Up to 2 metadata payloads optional
"network.example.config": 1 // Up to 1 config payload optional
}
};
// Utility class for working with payload sets
class PayloadSetValidator {
// Validate if a collection of payloads meets the requirements
static validate(payloads: Payload[], requirements: PayloadSet): {
valid: boolean;
missing: string[];
satisfied: string[];
counts: Record<string, number>;
} {
const counts: Record<string, number> = {};
const missing: string[] = [];
const satisfied: string[] = [];
// Count payloads by schema
payloads.forEach(payload => {
counts[payload.schema] = (counts[payload.schema] || 0) + 1;
});
// Check required schemas
if (requirements.required) {
Object.entries(requirements.required).forEach(([schema, required]) => {
const actual = counts[schema] || 0;
if (actual >= required) {
satisfied.push(schema);
} else {
missing.push(`${schema} (need ${required}, have ${actual})`);
}
});
}
// Check optional schemas (they're always satisfied if present)
if (requirements.optional) {
Object.entries(requirements.optional).forEach(([schema, _]) => {
if (counts[schema] > 0) {
satisfied.push(schema);
}
});
}
return {
valid: missing.length === 0,
missing,
satisfied,
counts
};
}
// Generate a report for payload set validation
static generateReport(payloads: Payload[], requirements: PayloadSet): string {
const result = this.validate(payloads, requirements);
let report = `Payload Set Validation Report\n`;
report += `================================\n`;
report += `Status: ${result.valid ? 'VALID' : 'INVALID'}\n\n`;
report += `Schema Counts:\n`;
Object.entries(result.counts).forEach(([schema, count]) => {
report += ` ${schema}: ${count}\n`;
});
if (result.satisfied.length > 0) {
report += `\nSatisfied Requirements:\n`;
result.satisfied.forEach(schema => {
report += ` ✓ ${schema}\n`;
});
}
if (result.missing.length > 0) {
report += `\nMissing Requirements:\n`;
result.missing.forEach(requirement => {
report += ` ✗ ${requirement}\n`;
});
}
return report;
}
// Filter payloads that match the set requirements
static filterMatchingPayloads(
allPayloads: Payload[],
requirements: PayloadSet
): Payload[] {
const requiredSchemas = Object.keys(requirements.required || {});
const optionalSchemas = Object.keys(requirements.optional || {});
const allowedSchemas = new Set([...requiredSchemas, ...optionalSchemas]);
return allPayloads.filter(payload =>
allowedSchemas.has(payload.schema)
);
}
}
// Usage examples
const testPayloads: Payload[] = [
{ schema: "network.example.user", name: "Alice", email: "alice@example.com" },
{ schema: "network.example.user", name: "Bob", email: "bob@example.com" },
{ schema: "network.example.session", sessionId: "sess123", userId: "alice" },
{ schema: "network.example.metadata", type: "analytics", data: {} },
{ schema: "network.example.config", theme: "dark", lang: "en" },
{ schema: "network.example.unknown", data: "should be filtered" }
];
// Validate against payload set requirements
const validation = PayloadSetValidator.validate(testPayloads, apiPayloadSet);
console.log("Validation result:", validation.valid);
console.log("Missing:", validation.missing);
// Generate detailed report
const report = PayloadSetValidator.generateReport(testPayloads, apiPayloadSet);
console.log(report);
// Filter matching payloads
const matchingPayloads = PayloadSetValidator.filterMatchingPayloads(
testPayloads,
apiPayloadSet
);
console.log("Matching payloads:", matchingPayloads.length); // Excludes unknown schemaUtility types and interfaces for working with temporal data in payloads.
/**
* Interface for objects with timestamp information
*/
interface Timestamp {
timestamp: number;
}
/**
* Utility type to add timestamp field to any object
*/
type WithTimestamp<T extends EmptyObject = EmptyObject> = T & Timestamp;Usage Examples:
import {
Timestamp,
WithTimestamp,
Payload
} from "@xyo-network/payload-model";
// Add timestamps to payload types
interface TimestampedUserPayload extends WithTimestamp<Payload> {
schema: "network.example.user";
name: string;
email: string;
}
// Create timestamped payload
const timestampedUser: TimestampedUserPayload = {
schema: "network.example.user",
name: "Alice",
email: "alice@example.com",
timestamp: Date.now()
};
// Utility functions for timestamps
class TimestampUtils {
// Add timestamp to existing payload
static addTimestamp<T extends Payload>(payload: T): WithTimestamp<T> {
return {
...payload,
timestamp: Date.now()
};
}
// Check if payload has timestamp
static hasTimestamp(payload: unknown): payload is Timestamp {
return typeof payload === 'object' &&
payload !== null &&
'timestamp' in payload &&
typeof (payload as any).timestamp === 'number';
}
// Sort payloads by timestamp
static sortByTimestamp<T extends Timestamp>(
payloads: T[],
order: 'asc' | 'desc' = 'desc'
): T[] {
return [...payloads].sort((a, b) => {
return order === 'desc'
? b.timestamp - a.timestamp
: a.timestamp - b.timestamp;
});
}
// Filter payloads by time range
static filterByTimeRange<T extends Timestamp>(
payloads: T[],
startTime: number,
endTime: number
): T[] {
return payloads.filter(payload =>
payload.timestamp >= startTime && payload.timestamp <= endTime
);
}
// Group payloads by time period
static groupByTimePeriod<T extends Timestamp>(
payloads: T[],
periodMs: number
): Record<string, T[]> {
const groups: Record<string, T[]> = {};
payloads.forEach(payload => {
const periodStart = Math.floor(payload.timestamp / periodMs) * periodMs;
const key = periodStart.toString();
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(payload);
});
return groups;
}
}
// Usage examples
const users: WithTimestamp<Payload>[] = [
{ schema: "network.example.user", name: "Alice", timestamp: Date.now() - 3600000 }, // 1 hour ago
{ schema: "network.example.user", name: "Bob", timestamp: Date.now() - 1800000 }, // 30 min ago
{ schema: "network.example.user", name: "Charlie", timestamp: Date.now() - 900000 } // 15 min ago
];
// Sort by timestamp
const sortedUsers = TimestampUtils.sortByTimestamp(users, 'asc');
console.log("Sorted users:", sortedUsers.map(u => u.name)); // ["Alice", "Bob", "Charlie"]
// Filter recent users (last 45 minutes)
const recentUsers = TimestampUtils.filterByTimeRange(
users,
Date.now() - 45 * 60 * 1000,
Date.now()
);
console.log("Recent users:", recentUsers.length); // 2
// Group by hour
const hourlyGroups = TimestampUtils.groupByTimePeriod(users, 60 * 60 * 1000);
console.log("Hourly groups:", Object.keys(hourlyGroups));
// Add timestamp to existing payload
const existingPayload: Payload = {
schema: "network.example.data",
data: "some data"
};
const timestampedPayload = TimestampUtils.addTimestamp(existingPayload);
console.log("Timestamped:", timestampedPayload.timestamp);Advanced utility types for complex payload type transformations and manipulations.
/**
* Utility types for deep property manipulation (from @xylabs/object)
*/
type DeepOmitStartsWith<T, Prefix extends string> = T; // Simplified representation
type DeepPickStartsWith<T, Prefix extends string> = T; // Simplified representation
/**
* Empty object type for type safety
*/
type EmptyObject = Record<string, never>;
/**
* JSON value type for flexible data storage
*/
type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };Usage Examples:
import {
Payload,
WithoutMeta,
WithoutClientMeta,
WithoutStorageMeta,
JsonValue
} from "@xyo-network/payload-model";
// Complex payload with various metadata
interface ComplexPayload extends Payload {
schema: "network.example.complex";
data: JsonValue;
// Client metadata (starts with $)
$userId?: string;
$sessionId?: string;
$clientVersion?: string;
// Storage metadata (starts with _)
_hash?: string;
_dataHash?: string;
_sequence?: string;
// Private storage metadata (starts with __)
__internalId?: string;
__debugInfo?: JsonValue;
}
// Create utility class for payload transformation
class PayloadTransformer {
// Remove all metadata for external API
static toExternalFormat<T extends Payload>(payload: T): WithoutMeta<T> {
const cleaned = { ...payload };
// Remove client metadata
Object.keys(cleaned).forEach(key => {
if (key.startsWith('$') || key.startsWith('_')) {
delete (cleaned as any)[key];
}
});
return cleaned as WithoutMeta<T>;
}
// Remove only client metadata
static removeClientMeta<T extends Payload>(payload: T): WithoutClientMeta<T> {
const cleaned = { ...payload };
Object.keys(cleaned).forEach(key => {
if (key.startsWith('$')) {
delete (cleaned as any)[key];
}
});
return cleaned as WithoutClientMeta<T>;
}
// Extract only metadata
static extractMetadata<T extends Payload>(payload: T): {
client: Record<string, any>;
storage: Record<string, any>;
private: Record<string, any>;
} {
const client: Record<string, any> = {};
const storage: Record<string, any> = {};
const private: Record<string, any> = {};
Object.entries(payload).forEach(([key, value]) => {
if (key.startsWith('__')) {
private[key] = value;
} else if (key.startsWith('_')) {
storage[key] = value;
} else if (key.startsWith('$')) {
client[key] = value;
}
});
return { client, storage, private };
}
// Merge metadata back into payload
static mergeMetadata<T extends Payload>(
payload: T,
metadata: {
client?: Record<string, any>;
storage?: Record<string, any>;
private?: Record<string, any>;
}
): T {
return {
...payload,
...metadata.client,
...metadata.storage,
...metadata.private
};
}
}
// Usage examples
const complexPayload: ComplexPayload = {
schema: "network.example.complex",
data: { message: "Hello World", count: 42 },
$userId: "user123",
$sessionId: "session456",
$clientVersion: "1.2.3",
_hash: "0x123...",
_dataHash: "0x456...",
_sequence: "seq789",
__internalId: "internal123",
__debugInfo: { trace: true, level: "debug" }
};
// Transform for external API
const externalPayload = PayloadTransformer.toExternalFormat(complexPayload);
console.log("External payload keys:", Object.keys(externalPayload));
// Only: ["schema", "data"]
// Remove client metadata only
const withoutClient = PayloadTransformer.removeClientMeta(complexPayload);
console.log("Without client metadata:", Object.keys(withoutClient));
// Includes storage metadata but not client metadata
// Extract metadata
const metadata = PayloadTransformer.extractMetadata(complexPayload);
console.log("Client metadata:", metadata.client);
console.log("Storage metadata:", metadata.storage);
console.log("Private metadata:", metadata.private);
// Work with JsonValue data
function processJsonData(data: JsonValue): string {
if (typeof data === 'string') return data;
if (typeof data === 'number') return data.toString();
if (typeof data === 'boolean') return data ? 'true' : 'false';
if (data === null) return 'null';
if (Array.isArray(data)) return `[${data.length} items]`;
if (typeof data === 'object') return `{${Object.keys(data).length} props}`;
return 'unknown';
}
const processed = processJsonData(complexPayload.data);
console.log("Processed data:", processed); // "{2 props}"import {
Payload,
PayloadFindFilter,
PayloadValueExpression,
WithTimestamp
} from "@xyo-network/payload-model";
// Create a comprehensive payload processing pipeline
class PayloadPipeline<T extends Payload> {
private processors: Array<(payload: T) => T> = [];
private validators: Array<(payload: T) => boolean> = [];
private extractors: Map<string, PayloadValueExpression<T, any, any>> = new Map();
// Add processing step
addProcessor(processor: (payload: T) => T): this {
this.processors.push(processor);
return this;
}
// Add validation step
addValidator(validator: (payload: T) => boolean): this {
this.validators.push(validator);
return this;
}
// Add value extractor
addExtractor<K extends keyof T>(
name: string,
extractor: PayloadValueExpression<T, K, any>
): this {
this.extractors.set(name, extractor);
return this;
}
// Process single payload
process(payload: T): {
success: boolean;
payload?: T;
extracted: Record<string, any>;
errors: string[];
} {
const errors: string[] = [];
const extracted: Record<string, any> = {};
let currentPayload = payload;
// Apply processors
try {
for (const processor of this.processors) {
currentPayload = processor(currentPayload);
}
} catch (error) {
errors.push(`Processing error: ${error}`);
return { success: false, extracted, errors };
}
// Apply validators
for (const validator of this.validators) {
if (!validator(currentPayload)) {
errors.push("Validation failed");
}
}
// Extract values
for (const [name, extractor] of this.extractors) {
try {
extracted[name] = extractor(currentPayload);
} catch (error) {
errors.push(`Extraction error for ${name}: ${error}`);
}
}
return {
success: errors.length === 0,
payload: errors.length === 0 ? currentPayload : undefined,
extracted,
errors
};
}
// Process batch of payloads
processBatch(payloads: T[]): {
successful: Array<{ payload: T; extracted: Record<string, any> }>;
failed: Array<{ original: T; errors: string[] }>;
} {
const successful: Array<{ payload: T; extracted: Record<string, any> }> = [];
const failed: Array<{ original: T; errors: string[] }> = [];
for (const payload of payloads) {
const result = this.process(payload);
if (result.success && result.payload) {
successful.push({ payload: result.payload, extracted: result.extracted });
} else {
failed.push({ original: payload, errors: result.errors });
}
}
return { successful, failed };
}
}
// Usage example
interface UserPayload extends WithTimestamp<Payload> {
schema: "network.example.user";
name: string;
email: string;
age: number;
}
const userPipeline = new PayloadPipeline<UserPayload>()
.addProcessor((payload) => ({
...payload,
name: payload.name.trim(),
email: payload.email.toLowerCase()
}))
.addValidator((payload) => payload.age >= 18)
.addValidator((payload) => payload.email.includes('@'))
.addExtractor('displayName', (payload) => `${payload.name} (${payload.age})`)
.addExtractor('domain', (payload) => payload.email.split('@')[1]);
const testUsers: UserPayload[] = [
{
schema: "network.example.user",
name: " Alice ",
email: "ALICE@EXAMPLE.COM",
age: 25,
timestamp: Date.now()
},
{
schema: "network.example.user",
name: "Bob",
email: "bob@test",
age: 16,
timestamp: Date.now()
}
];
const results = userPipeline.processBatch(testUsers);
console.log("Successful:", results.successful.length);
console.log("Failed:", results.failed.length);
results.successful.forEach(({ payload, extracted }) => {
console.log(`Processed: ${extracted.displayName} from ${extracted.domain}`);
});PayloadProperty<T>: Type representing all property keys of a payloadPayloadValue<T, Key>: Type representing the value of a specific payload propertyPayloadValueExpression<T, Key, TValue>: Function type for extracting property valuesPayloadFindFilter: Interface for payload filtering operationsPayloadHashMap<TPayload, TId>: Interface for efficient payload storage and lookupTimestamp: Interface for objects with timestamp informationWithTimestamp<T>: Utility type to add timestamp field to any objectEmptyObject: Empty object type for type safetyJsonValue: JSON value type for flexible data storageDeepOmitStartsWith<T, Prefix>: Remove properties starting with prefixDeepPickStartsWith<T, Prefix>: Select properties starting with prefixPayloadFindFilter.limit: Maximum number of resultsPayloadFindFilter.order: Sort order ('desc' | 'asc')PayloadFindFilter.schema: Schema filter (string or string array)PayloadHashMap.dataHash: Data hash mappings (Record<TId, TId>)PayloadHashMap.hash: Complete payload mappings (Record<TId, TPayload>)Install with Tessl CLI
npx tessl i tessl/npm-xyo-network--payload-model