0
# Payload Bundles and Queries
1
2
System for grouping related payloads and structured querying capabilities for payload discovery and filtering within the XYO Protocol 2.0 ecosystem.
3
4
## Capabilities
5
6
### Payload Bundle System
7
8
Payload bundles group multiple related payloads together with a root hash reference, enabling efficient handling of collections of related data in the XYO network.
9
10
```typescript { .api }
11
/**
12
* Schema constant for payload bundles
13
*/
14
const PayloadBundleSchema: "network.xyo.payload.bundle";
15
16
/**
17
* Type alias for the payload bundle schema
18
*/
19
type PayloadBundleSchema = typeof PayloadBundleSchema;
20
21
/**
22
* Fields interface for payload bundle data
23
*/
24
interface PayloadBundleFields<T extends Payload = Payload> {
25
/** Array of payloads contained in this bundle */
26
payloads: T[];
27
/** Root hash identifying the complete bundle */
28
root: Hash;
29
}
30
31
/**
32
* Complete payload bundle type combining fields with schema
33
*/
34
type PayloadBundle = Payload<PayloadBundleFields, PayloadBundleSchema>;
35
36
/**
37
* Type guard for payload bundle validation
38
*/
39
function isPayloadBundle(value: unknown): value is PayloadBundle;
40
41
/**
42
* Type assertion for payload bundle
43
*/
44
function asPayloadBundle(value: unknown): PayloadBundle;
45
46
/**
47
* Optional type assertion for payload bundle
48
*/
49
function asOptionalPayloadBundle(value: unknown): PayloadBundle | undefined;
50
```
51
52
**Usage Examples:**
53
54
```typescript
55
import {
56
PayloadBundle,
57
PayloadBundleFields,
58
PayloadBundleSchema,
59
isPayloadBundle,
60
asPayloadBundle,
61
Payload
62
} from "@xyo-network/payload-model";
63
64
// Define custom payload types for bundling
65
interface UserPayload extends Payload {
66
schema: "network.example.user";
67
name: string;
68
email: string;
69
}
70
71
interface ProductPayload extends Payload {
72
schema: "network.example.product";
73
name: string;
74
price: number;
75
}
76
77
// Create individual payloads
78
const userPayload: UserPayload = {
79
schema: "network.example.user",
80
name: "Alice",
81
email: "alice@example.com"
82
};
83
84
const productPayload: ProductPayload = {
85
schema: "network.example.product",
86
name: "Laptop",
87
price: 999
88
};
89
90
// Create a payload bundle
91
const bundle: PayloadBundle = {
92
schema: PayloadBundleSchema,
93
payloads: [userPayload, productPayload],
94
root: "0x1234567890abcdef..."
95
};
96
97
// Validate bundle
98
if (isPayloadBundle(bundle)) {
99
console.log(`Bundle contains ${bundle.payloads.length} payloads`);
100
console.log(`Root hash: ${bundle.root}`);
101
}
102
103
// Process bundles from unknown data
104
const unknownData: unknown = {
105
schema: PayloadBundleSchema,
106
payloads: [
107
{ schema: "network.example.user", name: "Bob", email: "bob@example.com" },
108
{ schema: "network.example.product", name: "Phone", price: 599 }
109
],
110
root: "0xabcdef1234567890..."
111
};
112
113
try {
114
const validBundle = asPayloadBundle(unknownData);
115
validBundle.payloads.forEach((payload, index) => {
116
console.log(`Payload ${index}: ${payload.schema}`);
117
});
118
} catch (error) {
119
console.error("Invalid bundle format");
120
}
121
122
// Create typed bundle for specific payload types
123
function createUserProductBundle(
124
users: UserPayload[],
125
products: ProductPayload[],
126
rootHash: string
127
): PayloadBundle {
128
return {
129
schema: PayloadBundleSchema,
130
payloads: [...users, ...products],
131
root: rootHash as Hash
132
};
133
}
134
```
135
136
### Query System
137
138
Structured query interface for payload discovery and filtering with support for address targeting, budget constraints, and frequency limitations.
139
140
```typescript { .api }
141
/**
142
* Query fields interface defining query parameters
143
*/
144
interface QueryFields {
145
/** The addresses of the intended handlers */
146
address?: Address | Address[];
147
148
/** The maximum XYO that can be spent executing the query */
149
budget?: number;
150
151
/** The frequency on which this query can be rerun */
152
maxFrequency?: 'once' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
153
154
/** The starting point for the bidding on the query */
155
minBid?: number;
156
}
157
158
/**
159
* Query payload type combining custom data with query fields
160
*/
161
type Query<T extends void | EmptyObject | WithSchema = void, S extends Schema | void = void> = Payload<
162
T extends void ? QueryFields : T & QueryFields,
163
S extends void
164
? T extends WithSchema ? T['schema']
165
: T extends void ? Schema
166
: void
167
: S
168
>;
169
```
170
171
**Usage Examples:**
172
173
```typescript
174
import { Query, QueryFields } from "@xyo-network/payload-model";
175
176
// Basic query with just query fields
177
type BasicQuery = Query;
178
179
const basicQuery: BasicQuery = {
180
schema: "network.xyo.query",
181
address: "0x742d35Cc6065C6EaABf23bA0aC21e0017E3BB26C",
182
budget: 1000,
183
maxFrequency: "hour",
184
minBid: 10
185
};
186
187
// Query with custom data
188
interface UserSearchQuery {
189
searchTerm: string;
190
filters: {
191
minAge?: number;
192
maxAge?: number;
193
location?: string;
194
};
195
}
196
197
const UserSearchSchema = "network.example.query.user-search" as const;
198
type UserSearchQueryPayload = Query<UserSearchQuery, typeof UserSearchSchema>;
199
200
const userSearchQuery: UserSearchQueryPayload = {
201
schema: UserSearchSchema,
202
searchTerm: "alice",
203
filters: {
204
minAge: 18,
205
location: "New York"
206
},
207
address: ["0x123...", "0x456..."],
208
budget: 500,
209
maxFrequency: "minute",
210
minBid: 5
211
};
212
213
// Query with multiple addresses
214
const multiAddressQuery: Query = {
215
schema: "network.xyo.multi-query",
216
address: [
217
"0x742d35Cc6065C6EaABf23bA0aC21e0017E3BB26C",
218
"0x8ba1f109551bD432803012645Hac136c73ce2A",
219
"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"
220
],
221
budget: 2000,
222
maxFrequency: "day"
223
};
224
225
// Query factory function
226
function createQuery<T>(
227
data: T,
228
schema: string,
229
options: Partial<QueryFields> = {}
230
): Query<T & { data: T }, typeof schema> {
231
return {
232
schema: schema as any,
233
data,
234
address: options.address,
235
budget: options.budget || 100,
236
maxFrequency: options.maxFrequency || "hour",
237
minBid: options.minBid || 1
238
} as Query<T & { data: T }, typeof schema>;
239
}
240
241
// Use query factory
242
const productQuery = createQuery(
243
{ category: "electronics", priceRange: [100, 1000] },
244
"network.example.query.product",
245
{
246
address: "0x742d35Cc6065C6EaABf23bA0aC21e0017E3BB26C",
247
budget: 300,
248
maxFrequency: "minute"
249
}
250
);
251
```
252
253
### Payload Collection Utilities
254
255
Additional utilities for working with collections of payloads and filtering operations.
256
257
```typescript { .api }
258
/**
259
* Filter interface for payload discovery operations
260
*/
261
interface PayloadFindFilter {
262
/** Maximum number of results to return */
263
limit?: number;
264
265
/** Sort order for results */
266
order?: 'desc' | 'asc';
267
268
/** Schema filter - single schema or array of schemas */
269
schema?: string | string[];
270
}
271
272
/**
273
* Hash map interface for efficient payload lookup
274
*/
275
interface PayloadHashMap<TPayload extends Payload = Payload, TId extends string | number | symbol = Hash> {
276
/** Data hash mappings - multiple root hashes may have same data hash */
277
dataHash: Record<TId, TId>;
278
279
/** Complete payload mappings by hash */
280
hash: Record<TId, TPayload>;
281
}
282
```
283
284
**Usage Examples:**
285
286
```typescript
287
import {
288
PayloadFindFilter,
289
PayloadHashMap,
290
Payload
291
} from "@xyo-network/payload-model";
292
293
// Create payload filter for search operations
294
const userFilter: PayloadFindFilter = {
295
limit: 10,
296
order: 'desc',
297
schema: ["network.example.user", "network.example.profile"]
298
};
299
300
const productFilter: PayloadFindFilter = {
301
limit: 50,
302
order: 'asc',
303
schema: "network.example.product"
304
};
305
306
// Simulate payload search function
307
function findPayloads(
308
payloads: Payload[],
309
filter: PayloadFindFilter
310
): Payload[] {
311
let filtered = payloads;
312
313
// Filter by schema
314
if (filter.schema) {
315
const schemas = Array.isArray(filter.schema) ? filter.schema : [filter.schema];
316
filtered = filtered.filter(p => schemas.includes(p.schema));
317
}
318
319
// Apply ordering (simplified example)
320
if (filter.order === 'desc') {
321
filtered = filtered.reverse();
322
}
323
324
// Apply limit
325
if (filter.limit) {
326
filtered = filtered.slice(0, filter.limit);
327
}
328
329
return filtered;
330
}
331
332
// Payload hash map for efficient lookups
333
interface UserPayload extends Payload {
334
schema: "network.example.user";
335
name: string;
336
email: string;
337
}
338
339
const payloadHashMap: PayloadHashMap<UserPayload> = {
340
dataHash: {
341
"0x123...": "0x123...",
342
"0x456...": "0x123...", // Same data hash
343
"0x789...": "0x789..."
344
},
345
hash: {
346
"0x123...": {
347
schema: "network.example.user",
348
name: "Alice",
349
email: "alice@example.com"
350
},
351
"0x456...": {
352
schema: "network.example.user",
353
name: "Alice",
354
email: "alice@example.com"
355
},
356
"0x789...": {
357
schema: "network.example.user",
358
name: "Bob",
359
email: "bob@example.com"
360
}
361
}
362
};
363
364
// Use hash map for lookups
365
function getPayloadByHash(hashMap: PayloadHashMap, hash: string): Payload | undefined {
366
return hashMap.hash[hash];
367
}
368
369
function getUniqueDataHashes(hashMap: PayloadHashMap): string[] {
370
return Object.values(hashMap.dataHash);
371
}
372
373
// Bundle operations with queries
374
function createBundleQuery(
375
bundleRoot: string,
376
targetAddress: string,
377
budget: number
378
): Query<{ bundleRoot: string }, "network.xyo.query.bundle"> {
379
return {
380
schema: "network.xyo.query.bundle",
381
bundleRoot,
382
address: targetAddress as Address,
383
budget,
384
maxFrequency: "hour",
385
minBid: 1
386
};
387
}
388
389
// Query for bundle contents
390
const bundleQuery = createBundleQuery(
391
"0x1234567890abcdef...",
392
"0x742d35Cc6065C6EaABf23bA0aC21e0017E3BB26C",
393
500
394
);
395
```
396
397
### PayloadSet System
398
399
System for defining collections of required and optional payloads with quantity specifications.
400
401
```typescript { .api }
402
/**
403
* Schema constant for payload sets
404
*/
405
const PayloadSetSchema: "network.xyo.payload.set";
406
407
/**
408
* PayloadSet interface defining required and optional payload quantities
409
*/
410
interface PayloadSet {
411
/** Optional payload requirements by schema with quantities */
412
optional?: Record<string, number>;
413
414
/** Required payload requirements by schema with quantities */
415
required?: Record<string, number>;
416
}
417
418
/**
419
* Complete PayloadSet payload type
420
*/
421
type PayloadSetPayload = Payload<PayloadSet, PayloadSetSchema>;
422
```
423
424
**Usage Examples:**
425
426
```typescript
427
import {
428
PayloadSet,
429
PayloadSetPayload,
430
PayloadSetSchema
431
} from "@xyo-network/payload-model";
432
433
// Define payload set requirements
434
const payloadSet: PayloadSetPayload = {
435
schema: PayloadSetSchema,
436
required: {
437
"network.example.user": 1,
438
"network.example.auth": 1
439
},
440
optional: {
441
"network.example.preferences": 1,
442
"network.example.metadata": 3
443
}
444
};
445
446
// Validate payload collection against PayloadSet
447
function validatePayloadCollection(
448
payloads: Payload[],
449
requirements: PayloadSet
450
): { valid: boolean; missing: string[]; errors: string[] } {
451
const payloadCounts = payloads.reduce((counts, payload) => {
452
counts[payload.schema] = (counts[payload.schema] || 0) + 1;
453
return counts;
454
}, {} as Record<string, number>);
455
456
const missing: string[] = [];
457
const errors: string[] = [];
458
459
// Check required payloads
460
if (requirements.required) {
461
for (const [schema, required] of Object.entries(requirements.required)) {
462
const actual = payloadCounts[schema] || 0;
463
if (actual < required) {
464
missing.push(`${schema} (need ${required}, have ${actual})`);
465
}
466
}
467
}
468
469
// Check optional payloads don't exceed limits
470
if (requirements.optional) {
471
for (const [schema, max] of Object.entries(requirements.optional)) {
472
const actual = payloadCounts[schema] || 0;
473
if (actual > max) {
474
errors.push(`${schema} exceeds maximum (max ${max}, have ${actual})`);
475
}
476
}
477
}
478
479
return {
480
valid: missing.length === 0 && errors.length === 0,
481
missing,
482
errors
483
};
484
}
485
486
// Use validation
487
const testPayloads: Payload[] = [
488
{ schema: "network.example.user", name: "Alice" },
489
{ schema: "network.example.auth", token: "abc123" },
490
{ schema: "network.example.preferences", theme: "dark" }
491
];
492
493
const validation = validatePayloadCollection(testPayloads, payloadSet);
494
console.log("Validation result:", validation);
495
```
496
497
## Advanced Usage Patterns
498
499
### Bundle Processing Pipeline
500
501
```typescript
502
import {
503
PayloadBundle,
504
PayloadBundleSchema,
505
isPayloadBundle,
506
Query,
507
PayloadFindFilter
508
} from "@xyo-network/payload-model";
509
510
// Bundle processing pipeline
511
class BundleProcessor {
512
async processBundle(data: unknown): Promise<ProcessedBundle | null> {
513
if (!isPayloadBundle(data)) {
514
return null;
515
}
516
517
const processed = {
518
root: data.root,
519
payloadCount: data.payloads.length,
520
schemas: [...new Set(data.payloads.map(p => p.schema))],
521
payloads: data.payloads
522
};
523
524
return processed;
525
}
526
527
createBundleFromQuery(query: Query, results: Payload[]): PayloadBundle {
528
return {
529
schema: PayloadBundleSchema,
530
payloads: results,
531
root: this.calculateRootHash(results)
532
};
533
}
534
535
private calculateRootHash(payloads: Payload[]): Hash {
536
// Simplified hash calculation
537
const combined = payloads.map(p => JSON.stringify(p)).join('');
538
return `0x${combined.slice(0, 64)}` as Hash;
539
}
540
}
541
542
interface ProcessedBundle {
543
root: Hash;
544
payloadCount: number;
545
schemas: string[];
546
payloads: Payload[];
547
}
548
```
549
550
### Query Builder Pattern
551
552
```typescript
553
import { Query, QueryFields, Address } from "@xyo-network/payload-model";
554
555
// Query builder for complex query construction
556
class QueryBuilder<T = {}> {
557
private data: T = {} as T;
558
private fields: Partial<QueryFields> = {};
559
private schemaValue: string = "network.xyo.query";
560
561
schema(schema: string): QueryBuilder<T> {
562
this.schemaValue = schema;
563
return this;
564
}
565
566
withData<U>(data: U): QueryBuilder<T & U> {
567
const builder = new QueryBuilder<T & U>();
568
builder.data = { ...this.data, ...data };
569
builder.fields = { ...this.fields };
570
builder.schemaValue = this.schemaValue;
571
return builder;
572
}
573
574
address(address: Address | Address[]): QueryBuilder<T> {
575
this.fields.address = address;
576
return this;
577
}
578
579
budget(budget: number): QueryBuilder<T> {
580
this.fields.budget = budget;
581
return this;
582
}
583
584
frequency(freq: QueryFields['maxFrequency']): QueryBuilder<T> {
585
this.fields.maxFrequency = freq;
586
return this;
587
}
588
589
minBid(bid: number): QueryBuilder<T> {
590
this.fields.minBid = bid;
591
return this;
592
}
593
594
build(): Query<T, typeof this.schemaValue> {
595
return {
596
schema: this.schemaValue,
597
...this.data,
598
...this.fields
599
} as Query<T, typeof this.schemaValue>;
600
}
601
}
602
603
// Usage
604
const query = new QueryBuilder()
605
.schema("network.example.user-search")
606
.withData({ searchTerm: "alice", filters: { location: "NYC" } })
607
.address("0x742d35Cc6065C6EaABf23bA0aC21e0017E3BB26C")
608
.budget(1000)
609
.frequency("minute")
610
.minBid(10)
611
.build();
612
```
613
614
## Types Reference
615
616
### Bundle Types
617
618
- **`PayloadBundle`**: Complete payload bundle type
619
- **`PayloadBundleFields<T>`**: Bundle data fields interface
620
- **`PayloadBundleSchema`**: Bundle schema constant
621
622
### Query Types
623
624
- **`Query<T, S>`**: Query payload type with custom data
625
- **`QueryFields`**: Query parameter fields interface
626
627
### Utility Types
628
629
- **`PayloadFindFilter`**: Filter interface for payload search
630
- **`PayloadHashMap<TPayload, TId>`**: Hash map for efficient payload lookup
631
- **`PayloadSet`**: Required/optional payload specifications
632
- **`PayloadSetPayload`**: PayloadSet as payload type
633
634
### Constants
635
636
- **`PayloadBundleSchema`**: "network.xyo.payload.bundle"
637
- **`PayloadSetSchema`**: "network.xyo.payload.set"
638
639
### Functions
640
641
- **`isPayloadBundle(value)`**: Type guard for payload bundles
642
- **`asPayloadBundle(value)`**: Type assertion for payload bundles
643
- **`asOptionalPayloadBundle(value)`**: Optional type assertion for payload bundles