Data
Purpose
The Data module defines the message payload structure with automatic schema generation, unique identification, and encryption key management. Data objects are the content carried within packets.
Key Interfaces
Data<T>
Logical view of data with deserialized message (used after parsing).
interface Data<T = unknown> {
pid: string // Process identifier
id: string // Unique message identifier (UUID)
sequence: number // Sequential counter within process
key: string // Encryption key for replies (UUID)
message: T // Deserialized message content
schema: Schema // JSON Schema describing message structure
schemaHash: string // SHA-256 hash of the schema
}
SerializedData<T>
Wire format with JSON-serialized message (used for transmission/encryption).
interface SerializedData<T = unknown> {
pid: string
id: string
sequence: number
key: string
message: JSONString<T> // JSON string representation
schema: Schema
schemaHash: string
}
JSONString<T>
Branded type for type-safe JSON strings.
type JSONString<T = unknown> = string & {
readonly __jsonBrand: unique symbol
readonly __type: T
}
Data Flow
Factory Functions
createDataFactory
Creates a data factory with injected hashing.
Signature:
function createDataFactory(createHash: (data: string, algorithm: string) => Promise<string>): DataCreater
Parameters:
| Parameter | Type | Description |
|---|---|---|
createHash |
(data: string, algorithm: string) => Promise<string> |
Hash function for schema hashing |
Returns: DataCreater - An async function that creates SerializedData<T> objects.
Example:
import { createHash } from '@hyperfrontend/cryptography/browser'
import { createDataFactory } from '@hyperfrontend/network-protocol/lib/data/creators'
const createData = createDataFactory(createHash)
const data = await createData(
'process-123', // pid
1, // sequence
{ type: 'greeting', content: 'Hello!' } // message
)
// data = {
// pid: 'process-123',
// id: 'generated-uuid',
// sequence: 1,
// key: 'generated-key-uuid',
// message: '{"type":"greeting","content":"Hello!"}',
// schema: { type: 'object', properties: { ... } },
// schemaHash: 'sha256-hash-of-schema'
// }
Helper Functions
deserializeData<T>
Converts SerializedData<T> to Data<T> by parsing the JSON message.
import { deserializeData } from '@hyperfrontend/network-protocol/lib/data'
const data = deserializeData(serializedData)
// data.message is now the parsed object
serializeData<T>
Converts Data<T> to SerializedData<T> by stringifying the message.
import { serializeData } from '@hyperfrontend/network-protocol/lib/data'
const serialized = serializeData(data)
// serialized.message is now a JSON string
asJSONString<T>
Safely casts a string to JSONString<T> for type safety.
import { asJSONString } from '@hyperfrontend/network-protocol/lib/data'
const jsonStr = asJSONString<MyType>('{"field":"value"}')
parseJSONString<T>
Parses a JSONString<T> back to its original type.
import { parseJSONString } from '@hyperfrontend/network-protocol/lib/data'
const obj = parseJSONString(jsonString)
// obj is typed as T
isJSONString<T>
Type guard to check if a value is a JSONString.
import { isJSONString } from '@hyperfrontend/network-protocol/lib/data'
if (isJSONString(value)) {
// value is JSONString<unknown>
}
Schema Generation
Schemas are automatically generated from your message structure:
const message = {
type: 'greeting',
count: 42,
active: true,
items: ['a', 'b'],
}
const data = await createData('pid', 1, message)
// data.schema = {
// type: 'object',
// properties: {
// type: { type: 'string' },
// count: { type: 'integer' },
// active: { type: 'boolean' },
// items: { type: 'array', items: { type: 'string' } }
// }
// }
The schema hash provides a fingerprint for message structure validation.
Encryption Key Management
Each data object includes a key field (auto-generated UUID):
const data = await createData('pid', 1, message)
console.log(data.key) // e.g., 'a1b2c3d4-e5f6-...'
This key is used for reply encryption:
- Sender generates a key and includes it in the message
- Receiver captures this key and uses it to encrypt responses
- This enables dynamic key exchange per message
Encryption/Decryption
createDataEncrypter
Creates an encrypter for SerializedData.
import { createDataEncrypter } from '@hyperfrontend/network-protocol/lib/data/security'
import { encrypt } from '@hyperfrontend/cryptography/browser'
const encryptData = createDataEncrypter(encrypt)
const encrypted = await encryptData(serializedData, 'password')
// encrypted is Uint8Array
createDataDecrypter
Creates a decrypter for encrypted data.
import { createDataDecrypter } from '@hyperfrontend/network-protocol/lib/data/security'
import { decrypt } from '@hyperfrontend/cryptography/browser'
const decryptData = createDataDecrypter(decrypt)
const serializedData = await decryptData(encryptedBytes, 'password')
Validation
Data creation validates all inputs:
// Invalid pid
await createData('', 1, message)
// Error: 'Cannot create data without a valid pid'
// Invalid sequence
await createData('pid', -1, message)
// Error: 'Cannot create data without a valid sequence'
// Circular references
const circular = { self: null }
circular.self = circular
await createData('pid', 1, circular)
// Error: 'Cannot create data with a message with circular references'
// Invalid message
await createData('pid', 1, undefined)
// Error: 'Cannot create data without a valid message'
Relationship to Other Modules
See Also
- Library Index - All modules
- Architecture Guide - Data architecture
- Browser Entry - Browser-specific data
- Node Entry - Node.js-specific data
Related Modules
| Module | Relationship |
|---|---|
| packet/ | Data is payload of UnencryptedPacket |