mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-24 05:12:24 +02:00
update docs
This commit is contained in:
@@ -1151,21 +1151,222 @@ process.on('SIGINT', async () => {
|
||||
|
||||
## 📚 API Reference
|
||||
|
||||
### Network Interface
|
||||
### NetworkClient Interface
|
||||
|
||||
The core `Network` interface provides:
|
||||
The `NetworkClient` interface is the main entry point for interacting with the Huly Virtual Network:
|
||||
|
||||
- `register(record, agent)`: Register an agent with the network
|
||||
- `unregister(agentId)`: Unregister an agent from the network
|
||||
- `ping(agentId | clientId)`: Mark an agent or client as alive
|
||||
- `get(client, uuid, request)`: Get or create a container
|
||||
- `list(kind)`: List containers of a specific kind
|
||||
- `release(client, uuid)`: Release a container reference
|
||||
- `request(target, operation, data)`: Send request to container
|
||||
- `agents()`: Get all registered agents
|
||||
- `kinds()`: Get all supported container kinds
|
||||
- `register(agent)`: Register a NetworkAgent to be processed by the network
|
||||
- `agents()`: Get all registered agents with their information
|
||||
- `kinds()`: Get a full unique set of supported container kinds
|
||||
- `get(kind, options)`: Get or start a container of the specified kind
|
||||
- `list(kind?)`: List all containers, optionally filtered by kind
|
||||
- `request(target, operation, data?)`: Send a request to a container using proxy connection
|
||||
- `onUpdate(listener)`: Register a listener for network events (returns unsubscribe function)
|
||||
- `waitConnection(timeout?)`: Wait for network connection (0 = wait indefinitely)
|
||||
- `close()`: Close the client connection
|
||||
|
||||
### Agent Interface
|
||||
### ClientWithAgents Interface
|
||||
|
||||
The `ClientWithAgents` interface extends `NetworkClient` and is returned by `createNetworkClient()`. It adds agent hosting capabilities:
|
||||
|
||||
- **All NetworkClient methods** (listed above)
|
||||
- `serveAgent(endpointUrl, factory, statelessContainers?)`: Create and register an agent with container factories
|
||||
|
||||
#### serveAgent Method
|
||||
|
||||
The `serveAgent` method allows a client to act as both a client and an agent host:
|
||||
|
||||
```typescript
|
||||
serveAgent(
|
||||
endpointUrl: string,
|
||||
factory: Record<ContainerKind, ContainerFactory>,
|
||||
statelessContainers?: StatelessContainersFactory
|
||||
): Promise<void>
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `endpointUrl`: The endpoint URL for the agent (e.g., `'localhost:3738'`)
|
||||
- `factory`: A record mapping container kinds to factory functions for creating containers on-demand
|
||||
- `statelessContainers`: Optional factory for creating stateless containers that support high availability
|
||||
|
||||
**Basic Usage Example:**
|
||||
|
||||
```typescript
|
||||
import { createNetworkClient, containerOnAgentEndpointRef } from '@hcengineering/network-client'
|
||||
import type { Container, ContainerUuid, ClientUuid } from '@hcengineering/network-core'
|
||||
|
||||
// 1. Create a container implementation
|
||||
class MyServiceContainer implements Container {
|
||||
constructor(readonly uuid: ContainerUuid) {}
|
||||
|
||||
async request(operation: string, data?: any): Promise<any> {
|
||||
return { success: true, operation, data }
|
||||
}
|
||||
|
||||
async ping(): Promise<void> {}
|
||||
async terminate(): Promise<void> {}
|
||||
connect(clientId: ClientUuid, broadcast: (data: any) => Promise<void>): void {}
|
||||
disconnect(clientId: ClientUuid): void {}
|
||||
}
|
||||
|
||||
// 2. Connect and serve an agent
|
||||
const client = createNetworkClient('localhost:3737')
|
||||
await client.waitConnection(5000)
|
||||
|
||||
await client.serveAgent('localhost:3738', {
|
||||
'my-service': async (options, agentEndpoint) => {
|
||||
const uuid = options.uuid ?? (`container-${Date.now()}` as ContainerUuid)
|
||||
const container = new MyServiceContainer(uuid)
|
||||
return {
|
||||
uuid,
|
||||
container,
|
||||
endpoint: containerOnAgentEndpointRef(agentEndpoint!, uuid)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 3. Now this client can also request containers
|
||||
const containerRef = await client.get('my-service' as any, {})
|
||||
const result = await containerRef.request('test', { value: 42 })
|
||||
await containerRef.close()
|
||||
```
|
||||
|
||||
**High Availability Example with Stateless Containers:**
|
||||
|
||||
```typescript
|
||||
import { createNetworkClient, containerOnAgentEndpointRef } from '@hcengineering/network-client'
|
||||
import type { Container, ContainerUuid, ContainerKind } from '@hcengineering/network-core'
|
||||
|
||||
class LeaderServiceContainer implements Container {
|
||||
constructor(readonly uuid: ContainerUuid, readonly instanceName: string) {}
|
||||
|
||||
async request(operation: string, data?: any): Promise<any> {
|
||||
return { instance: this.instanceName, operation, data }
|
||||
}
|
||||
|
||||
async ping(): Promise<void> {}
|
||||
async terminate(): Promise<void> {}
|
||||
connect(clientId: any, broadcast: (data: any) => Promise<void>): void {}
|
||||
disconnect(clientId: any): void {}
|
||||
}
|
||||
|
||||
// Shared UUID for HA failover
|
||||
const leaderUuid = 'service-leader-001' as ContainerUuid
|
||||
|
||||
// Primary agent
|
||||
const primaryClient = createNetworkClient('localhost:3737')
|
||||
await primaryClient.waitConnection(5000)
|
||||
|
||||
await primaryClient.serveAgent(
|
||||
'localhost:3801',
|
||||
{}, // No on-demand factories
|
||||
(agentEndpoint) => {
|
||||
// Stateless container for automatic failover
|
||||
const container = new LeaderServiceContainer(leaderUuid, 'Primary')
|
||||
return [
|
||||
{
|
||||
uuid: leaderUuid,
|
||||
kind: 'leader-service' as ContainerKind,
|
||||
endpoint: containerOnAgentEndpointRef(agentEndpoint, leaderUuid),
|
||||
container
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
// Secondary agent (backup)
|
||||
const secondaryClient = createNetworkClient('localhost:3737')
|
||||
await secondaryClient.waitConnection(5000)
|
||||
|
||||
await secondaryClient.serveAgent('localhost:3802', {}, (agentEndpoint) => {
|
||||
const container = new LeaderServiceContainer(leaderUuid, 'Secondary')
|
||||
return [
|
||||
{
|
||||
uuid: leaderUuid,
|
||||
kind: 'leader-service' as ContainerKind,
|
||||
endpoint: containerOnAgentEndpointRef(agentEndpoint, leaderUuid),
|
||||
container
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// Primary wins, Secondary automatically takes over if Primary fails
|
||||
const leaderRef = await primaryClient.get('leader-service' as any, { uuid: leaderUuid })
|
||||
const result = await leaderRef.request('status')
|
||||
console.log('Active leader:', result.instance) // "Primary"
|
||||
```
|
||||
|
||||
**Multi-Tenant Example:**
|
||||
|
||||
```typescript
|
||||
class TenantContainer implements Container {
|
||||
constructor(readonly uuid: ContainerUuid, readonly tenantId: string) {}
|
||||
|
||||
async request(operation: string, data?: any): Promise<any> {
|
||||
return { tenantId: this.tenantId, operation, data }
|
||||
}
|
||||
|
||||
async ping(): Promise<void> {}
|
||||
async terminate(): Promise<void> {}
|
||||
connect(clientId: any, broadcast: (data: any) => Promise<void>): void {}
|
||||
disconnect(clientId: any): void {}
|
||||
}
|
||||
|
||||
const client = createNetworkClient('localhost:3737')
|
||||
await client.waitConnection(5000)
|
||||
|
||||
await client.serveAgent('localhost:3738', {
|
||||
'tenant-workspace': async (options, agentEndpoint) => {
|
||||
const tenantId = options.labels?.[0] || 'default'
|
||||
const uuid = options.uuid ?? (`workspace-${tenantId}` as ContainerUuid)
|
||||
const container = new TenantContainer(uuid, tenantId)
|
||||
return {
|
||||
uuid,
|
||||
container,
|
||||
endpoint: containerOnAgentEndpointRef(agentEndpoint!, uuid)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Request tenant-specific containers
|
||||
const tenant1 = await client.get('tenant-workspace' as any, { labels: ['tenant-1'] })
|
||||
const tenant2 = await client.get('tenant-workspace' as any, { labels: ['tenant-2'] })
|
||||
|
||||
// Each tenant has isolated containers
|
||||
await tenant1.request('getData')
|
||||
await tenant2.request('getData')
|
||||
```
|
||||
|
||||
**See Also:**
|
||||
|
||||
- [Quick Start Example](#-getting-started) - Basic `serveAgent` usage
|
||||
- [HA Stateless Containers Example](examples/ha-stateless-container-example.ts) - Full HA setup with `serveAgent`
|
||||
- [Production Setup Example](examples/04-complete-production-setup.ts) - Complete production configuration
|
||||
|
||||
### ContainerReference Interface
|
||||
|
||||
The `ContainerReference` is returned by `client.get()` and represents a reference to a container:
|
||||
|
||||
- `uuid`: The unique identifier of the container
|
||||
- `endpoint`: The container's endpoint reference
|
||||
- `request(operation, data?)`: Send a request to the container
|
||||
- `connect()`: Establish a direct connection to the container (returns `ContainerConnection`)
|
||||
- `cast<T>(interfaceName?)`: Create a typed proxy for the container
|
||||
- `close()`: Release the container reference
|
||||
- `onEndpointUpdate?()`: Optional callback when container endpoint changes
|
||||
|
||||
### ContainerConnection Interface
|
||||
|
||||
The `ContainerConnection` is returned by `containerRef.connect()` for direct bidirectional communication:
|
||||
|
||||
- `containerId`: The UUID of the connected container
|
||||
- `request(operation, data?)`: Send a request to the container
|
||||
- `cast<T>(interfaceName?)`: Create a typed proxy for the connection
|
||||
- `on?(data)`: Optional handler for receiving notifications from the container
|
||||
- `close()`: Close the connection
|
||||
|
||||
### NetworkAgent Interface
|
||||
|
||||
The `NetworkAgent` interface defines:
|
||||
|
||||
@@ -1187,16 +1388,6 @@ The `Container` interface includes:
|
||||
- `ping()`: Health check response
|
||||
- Optional: `onTerminated()`: Cleanup callback
|
||||
|
||||
### TickManager Interface
|
||||
|
||||
The `TickManager` handles time-based operations:
|
||||
|
||||
- `now()`: Get current timestamp
|
||||
- `register(handler, interval)`: Register periodic handler (interval in seconds)
|
||||
- `start()`: Start the tick manager
|
||||
- `stop()`: Stop the tick manager
|
||||
- `waitTick(ticks)`: Wait for specific number of ticks
|
||||
|
||||
## 🏗️ Building Applications
|
||||
|
||||
### Container Types
|
||||
|
||||
Generated
+2
-28
@@ -106,8 +106,8 @@ importers:
|
||||
version: 8.3.2
|
||||
devDependencies:
|
||||
'@hcengineering/platform-rig':
|
||||
specifier: ^0.7.4
|
||||
version: 0.7.4(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-config-standard-with-typescript@40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2)
|
||||
specifier: ^0.7.8
|
||||
version: 0.7.8(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-config-standard-with-typescript@40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2)
|
||||
'@types/jest':
|
||||
specifier: ^29.5.5
|
||||
version: 29.5.14
|
||||
@@ -984,19 +984,6 @@ packages:
|
||||
resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
'@hcengineering/platform-rig@0.7.4':
|
||||
resolution: {integrity: sha512-NiUaWYDfXN5UEzReOfRjiGnRNYxU1N/QL0VMCLGjKUcogrMMSdMfVZDt1IdTXrgAllMyim57lXMaeX8vR38ZoQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@typescript-eslint/eslint-plugin': ^6.11.0
|
||||
'@typescript-eslint/parser': ^6.11.0
|
||||
eslint: ^8.54.0
|
||||
eslint-config-standard-with-typescript: ^40.0.0
|
||||
eslint-plugin-import: ^2.26.0
|
||||
eslint-plugin-n: ^15.4.0
|
||||
eslint-plugin-promise: ^6.1.1
|
||||
prettier: ^3.0.0
|
||||
|
||||
'@hcengineering/platform-rig@0.7.8':
|
||||
resolution: {integrity: sha512-w19uz2e+pCsn6nuDGvpw5Gl33foVMYo6FaHRL1icVDAxaA9RMRE3SNYuroxOv4XzjNu/mhFo9XU6QuJB2ta1Xg==}
|
||||
hasBin: true
|
||||
@@ -3337,19 +3324,6 @@ snapshots:
|
||||
|
||||
'@eslint/js@8.57.1': {}
|
||||
|
||||
'@hcengineering/platform-rig@0.7.4(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-config-standard-with-typescript@40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.2)
|
||||
esbuild: 0.25.9
|
||||
esbuild-plugin-copy: 2.1.1(esbuild@0.25.9)
|
||||
eslint: 8.57.1
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.9.2)
|
||||
eslint-plugin-import: 2.32.0(eslint@8.57.1)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.57.1)
|
||||
eslint-plugin-promise: 6.6.0(eslint@8.57.1)
|
||||
prettier: 3.6.2
|
||||
|
||||
'@hcengineering/platform-rig@0.7.8(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-config-standard-with-typescript@40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.9.2))(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2)
|
||||
|
||||
Reference in New Issue
Block a user