@xtr-dev/rondevu-client 0.20.1 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -385
- package/dist/api/batcher.d.ts +60 -38
- package/dist/api/batcher.js +121 -77
- package/dist/api/client.d.ts +104 -61
- package/dist/api/client.js +273 -185
- package/dist/connections/answerer.d.ts +15 -6
- package/dist/connections/answerer.js +56 -19
- package/dist/connections/base.d.ts +6 -4
- package/dist/connections/base.js +26 -16
- package/dist/connections/config.d.ts +30 -0
- package/dist/connections/config.js +20 -0
- package/dist/connections/events.d.ts +6 -6
- package/dist/connections/offerer.d.ts +37 -8
- package/dist/connections/offerer.js +92 -24
- package/dist/core/ice-config.d.ts +35 -0
- package/dist/core/ice-config.js +111 -0
- package/dist/core/index.d.ts +18 -18
- package/dist/core/index.js +18 -13
- package/dist/core/offer-pool.d.ts +30 -11
- package/dist/core/offer-pool.js +90 -76
- package/dist/core/peer.d.ts +155 -0
- package/dist/core/peer.js +252 -0
- package/dist/core/polling-manager.d.ts +71 -0
- package/dist/core/polling-manager.js +122 -0
- package/dist/core/rondevu-errors.d.ts +59 -0
- package/dist/core/rondevu-errors.js +75 -0
- package/dist/core/rondevu-types.d.ts +125 -0
- package/dist/core/rondevu-types.js +6 -0
- package/dist/core/rondevu.d.ts +106 -209
- package/dist/core/rondevu.js +221 -349
- package/dist/crypto/adapter.d.ts +25 -9
- package/dist/crypto/node.d.ts +27 -5
- package/dist/crypto/node.js +96 -25
- package/dist/crypto/web.d.ts +26 -4
- package/dist/crypto/web.js +102 -25
- package/dist/utils/message-buffer.js +4 -4
- package/dist/webrtc/adapter.d.ts +22 -0
- package/dist/webrtc/adapter.js +5 -0
- package/dist/webrtc/browser.d.ts +12 -0
- package/dist/webrtc/browser.js +15 -0
- package/dist/webrtc/node.d.ts +32 -0
- package/dist/webrtc/node.js +32 -0
- package/package.json +17 -6
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PollingManager - Centralized polling for WebRTC signaling
|
|
3
|
+
*
|
|
4
|
+
* Provides a single shared polling timer that emits events for:
|
|
5
|
+
* - poll:answer - When an offer receives an answer
|
|
6
|
+
* - poll:ice - When new ICE candidates are available
|
|
7
|
+
*
|
|
8
|
+
* Connections subscribe to these events and filter by offerId in their callbacks.
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'eventemitter3';
|
|
11
|
+
import { RondevuAPI, IceCandidate } from '../api/client.js';
|
|
12
|
+
export interface PollAnswerEvent {
|
|
13
|
+
offerId: string;
|
|
14
|
+
answererId: string;
|
|
15
|
+
sdp: string;
|
|
16
|
+
answeredAt: number;
|
|
17
|
+
}
|
|
18
|
+
export interface PollIceEvent {
|
|
19
|
+
offerId: string;
|
|
20
|
+
candidates: IceCandidate[];
|
|
21
|
+
}
|
|
22
|
+
export interface PollingManagerEvents {
|
|
23
|
+
'poll:answer': (data: PollAnswerEvent) => void;
|
|
24
|
+
'poll:ice': (data: PollIceEvent) => void;
|
|
25
|
+
'poll:error': (error: Error) => void;
|
|
26
|
+
'poll:started': () => void;
|
|
27
|
+
'poll:stopped': () => void;
|
|
28
|
+
}
|
|
29
|
+
export interface PollingManagerOptions {
|
|
30
|
+
api: RondevuAPI;
|
|
31
|
+
intervalMs?: number;
|
|
32
|
+
debugEnabled?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Centralized polling manager that emits global events
|
|
36
|
+
* Connections subscribe to events and filter by offerId
|
|
37
|
+
*/
|
|
38
|
+
export declare class PollingManager extends EventEmitter<PollingManagerEvents> {
|
|
39
|
+
private static readonly DEFAULT_INTERVAL_MS;
|
|
40
|
+
private readonly api;
|
|
41
|
+
private readonly intervalMs;
|
|
42
|
+
private readonly debugEnabled;
|
|
43
|
+
private pollingInterval;
|
|
44
|
+
private lastPollTimestamp;
|
|
45
|
+
private running;
|
|
46
|
+
constructor(options: PollingManagerOptions);
|
|
47
|
+
/**
|
|
48
|
+
* Start polling
|
|
49
|
+
*/
|
|
50
|
+
start(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Stop polling
|
|
53
|
+
*/
|
|
54
|
+
stop(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Check if polling is active
|
|
57
|
+
*/
|
|
58
|
+
isRunning(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Get the last poll timestamp
|
|
61
|
+
*/
|
|
62
|
+
getLastPollTimestamp(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Perform a single poll
|
|
65
|
+
*/
|
|
66
|
+
private poll;
|
|
67
|
+
/**
|
|
68
|
+
* Debug logging
|
|
69
|
+
*/
|
|
70
|
+
private debug;
|
|
71
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PollingManager - Centralized polling for WebRTC signaling
|
|
3
|
+
*
|
|
4
|
+
* Provides a single shared polling timer that emits events for:
|
|
5
|
+
* - poll:answer - When an offer receives an answer
|
|
6
|
+
* - poll:ice - When new ICE candidates are available
|
|
7
|
+
*
|
|
8
|
+
* Connections subscribe to these events and filter by offerId in their callbacks.
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'eventemitter3';
|
|
11
|
+
/**
|
|
12
|
+
* Centralized polling manager that emits global events
|
|
13
|
+
* Connections subscribe to events and filter by offerId
|
|
14
|
+
*/
|
|
15
|
+
export class PollingManager extends EventEmitter {
|
|
16
|
+
constructor(options) {
|
|
17
|
+
super();
|
|
18
|
+
this.pollingInterval = null;
|
|
19
|
+
this.lastPollTimestamp = 0;
|
|
20
|
+
this.running = false;
|
|
21
|
+
this.api = options.api;
|
|
22
|
+
this.intervalMs = options.intervalMs ?? PollingManager.DEFAULT_INTERVAL_MS;
|
|
23
|
+
this.debugEnabled = options.debugEnabled ?? false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Start polling
|
|
27
|
+
*/
|
|
28
|
+
start() {
|
|
29
|
+
if (this.running) {
|
|
30
|
+
this.debug('Already running');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.debug('Starting polling manager');
|
|
34
|
+
this.running = true;
|
|
35
|
+
// Poll immediately
|
|
36
|
+
this.poll();
|
|
37
|
+
// Start interval
|
|
38
|
+
this.pollingInterval = setInterval(() => {
|
|
39
|
+
this.poll();
|
|
40
|
+
}, this.intervalMs);
|
|
41
|
+
this.emit('poll:started');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Stop polling
|
|
45
|
+
*/
|
|
46
|
+
stop() {
|
|
47
|
+
if (!this.running)
|
|
48
|
+
return;
|
|
49
|
+
this.debug('Stopping polling manager');
|
|
50
|
+
this.running = false;
|
|
51
|
+
if (this.pollingInterval) {
|
|
52
|
+
clearInterval(this.pollingInterval);
|
|
53
|
+
this.pollingInterval = null;
|
|
54
|
+
}
|
|
55
|
+
this.emit('poll:stopped');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if polling is active
|
|
59
|
+
*/
|
|
60
|
+
isRunning() {
|
|
61
|
+
return this.running;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the last poll timestamp
|
|
65
|
+
*/
|
|
66
|
+
getLastPollTimestamp() {
|
|
67
|
+
return this.lastPollTimestamp;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Perform a single poll
|
|
71
|
+
*/
|
|
72
|
+
async poll() {
|
|
73
|
+
if (!this.running)
|
|
74
|
+
return;
|
|
75
|
+
try {
|
|
76
|
+
const result = await this.api.poll(this.lastPollTimestamp);
|
|
77
|
+
// Emit answer events
|
|
78
|
+
for (const answer of result.answers) {
|
|
79
|
+
this.debug(`Poll: answer for ${answer.offerId}`);
|
|
80
|
+
this.emit('poll:answer', {
|
|
81
|
+
offerId: answer.offerId,
|
|
82
|
+
answererId: answer.answererId,
|
|
83
|
+
sdp: answer.sdp,
|
|
84
|
+
answeredAt: answer.answeredAt,
|
|
85
|
+
});
|
|
86
|
+
// Update last poll timestamp
|
|
87
|
+
if (answer.answeredAt > this.lastPollTimestamp) {
|
|
88
|
+
this.lastPollTimestamp = answer.answeredAt;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Emit ICE candidate events (grouped by offerId)
|
|
92
|
+
for (const [offerId, candidates] of Object.entries(result.iceCandidates)) {
|
|
93
|
+
if (candidates.length > 0) {
|
|
94
|
+
this.debug(`Poll: ${candidates.length} ICE candidates for ${offerId}`);
|
|
95
|
+
this.emit('poll:ice', {
|
|
96
|
+
offerId,
|
|
97
|
+
candidates: candidates,
|
|
98
|
+
});
|
|
99
|
+
// Update last poll timestamp from candidates
|
|
100
|
+
for (const candidate of candidates) {
|
|
101
|
+
if (candidate.createdAt > this.lastPollTimestamp) {
|
|
102
|
+
this.lastPollTimestamp = candidate.createdAt;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
this.debug('Poll error:', error);
|
|
110
|
+
this.emit('poll:error', error instanceof Error ? error : new Error(String(error)));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Debug logging
|
|
115
|
+
*/
|
|
116
|
+
debug(...args) {
|
|
117
|
+
if (this.debugEnabled) {
|
|
118
|
+
console.log('[PollingManager]', ...args);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
PollingManager.DEFAULT_INTERVAL_MS = 1000;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rondevu Error Classes
|
|
3
|
+
*
|
|
4
|
+
* Error hierarchy for the Rondevu client:
|
|
5
|
+
* - RondevuError (base)
|
|
6
|
+
* - NetworkError (API/connectivity issues)
|
|
7
|
+
* - ValidationError (invalid input/data)
|
|
8
|
+
* - ConnectionError (WebRTC/ICE issues)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Base error class for all Rondevu errors.
|
|
12
|
+
* Provides optional context object for debugging.
|
|
13
|
+
*/
|
|
14
|
+
export declare class RondevuError extends Error {
|
|
15
|
+
context?: Record<string, unknown> | undefined;
|
|
16
|
+
constructor(message: string, context?: Record<string, unknown> | undefined);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Network-related errors (API calls, connectivity)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* throw new NetworkError('Failed to reach signaling server', {
|
|
24
|
+
* url: 'https://api.ronde.vu',
|
|
25
|
+
* status: 503
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class NetworkError extends RondevuError {
|
|
30
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Validation errors (invalid input, malformed data)
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* throw new ValidationError('Invalid username format', {
|
|
38
|
+
* username: 'invalid@user',
|
|
39
|
+
* pattern: '^[a-z0-9-]{4,32}$'
|
|
40
|
+
* })
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare class ValidationError extends RondevuError {
|
|
44
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* WebRTC connection errors (peer connection failures, ICE issues)
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* throw new ConnectionError('ICE connection failed', {
|
|
52
|
+
* iceState: 'failed',
|
|
53
|
+
* offerId: 'abc123'
|
|
54
|
+
* })
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare class ConnectionError extends RondevuError {
|
|
58
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
59
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rondevu Error Classes
|
|
3
|
+
*
|
|
4
|
+
* Error hierarchy for the Rondevu client:
|
|
5
|
+
* - RondevuError (base)
|
|
6
|
+
* - NetworkError (API/connectivity issues)
|
|
7
|
+
* - ValidationError (invalid input/data)
|
|
8
|
+
* - ConnectionError (WebRTC/ICE issues)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Base error class for all Rondevu errors.
|
|
12
|
+
* Provides optional context object for debugging.
|
|
13
|
+
*/
|
|
14
|
+
export class RondevuError extends Error {
|
|
15
|
+
constructor(message, context) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.context = context;
|
|
18
|
+
this.name = 'RondevuError';
|
|
19
|
+
Object.setPrototypeOf(this, RondevuError.prototype);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Network-related errors (API calls, connectivity)
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* throw new NetworkError('Failed to reach signaling server', {
|
|
28
|
+
* url: 'https://api.ronde.vu',
|
|
29
|
+
* status: 503
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class NetworkError extends RondevuError {
|
|
34
|
+
constructor(message, context) {
|
|
35
|
+
super(message, context);
|
|
36
|
+
this.name = 'NetworkError';
|
|
37
|
+
Object.setPrototypeOf(this, NetworkError.prototype);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Validation errors (invalid input, malformed data)
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* throw new ValidationError('Invalid username format', {
|
|
46
|
+
* username: 'invalid@user',
|
|
47
|
+
* pattern: '^[a-z0-9-]{4,32}$'
|
|
48
|
+
* })
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export class ValidationError extends RondevuError {
|
|
52
|
+
constructor(message, context) {
|
|
53
|
+
super(message, context);
|
|
54
|
+
this.name = 'ValidationError';
|
|
55
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* WebRTC connection errors (peer connection failures, ICE issues)
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* throw new ConnectionError('ICE connection failed', {
|
|
64
|
+
* iceState: 'failed',
|
|
65
|
+
* offerId: 'abc123'
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export class ConnectionError extends RondevuError {
|
|
70
|
+
constructor(message, context) {
|
|
71
|
+
super(message, context);
|
|
72
|
+
this.name = 'ConnectionError';
|
|
73
|
+
Object.setPrototypeOf(this, ConnectionError.prototype);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rondevu Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Contains all public interfaces and types for the Rondevu client.
|
|
5
|
+
*/
|
|
6
|
+
import { Credential } from '../api/client.js';
|
|
7
|
+
import { CryptoAdapter } from '../crypto/adapter.js';
|
|
8
|
+
import { WebRTCAdapter } from '../webrtc/adapter.js';
|
|
9
|
+
import { ConnectionConfig } from '../connections/config.js';
|
|
10
|
+
import { IceServerPreset } from './ice-config.js';
|
|
11
|
+
/**
|
|
12
|
+
* Options for creating a Rondevu instance via Rondevu.connect()
|
|
13
|
+
*/
|
|
14
|
+
export interface RondevuOptions {
|
|
15
|
+
/** API URL (defaults to 'https://api.ronde.vu') */
|
|
16
|
+
apiUrl?: string;
|
|
17
|
+
/** Pre-existing credential (will generate if not provided) */
|
|
18
|
+
credential?: Credential;
|
|
19
|
+
/** Claim specific username (4-32 chars, alphanumeric + dashes + periods) */
|
|
20
|
+
username?: string;
|
|
21
|
+
/** Crypto adapter (defaults to WebCryptoAdapter) */
|
|
22
|
+
cryptoAdapter?: CryptoAdapter;
|
|
23
|
+
/** WebRTC adapter (defaults to BrowserWebRTCAdapter, use NodeWebRTCAdapter for Node.js) */
|
|
24
|
+
webrtcAdapter?: WebRTCAdapter;
|
|
25
|
+
/** ICE server preset name or custom RTCIceServer array */
|
|
26
|
+
iceServers?: IceServerPreset | RTCIceServer[];
|
|
27
|
+
/** Enable debug logging (default: false) */
|
|
28
|
+
debug?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Context returned by offer factory functions
|
|
32
|
+
*/
|
|
33
|
+
export interface OfferContext {
|
|
34
|
+
/** Optional data channel created for the offer */
|
|
35
|
+
dc?: RTCDataChannel;
|
|
36
|
+
/** The WebRTC offer SDP */
|
|
37
|
+
offer: RTCSessionDescriptionInit;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Factory function for creating WebRTC offers.
|
|
41
|
+
* Rondevu creates the RTCPeerConnection and passes it to the factory,
|
|
42
|
+
* allowing ICE candidate handlers to be set up before setLocalDescription() is called.
|
|
43
|
+
*
|
|
44
|
+
* @param pc - The RTCPeerConnection created by Rondevu (already configured with ICE servers)
|
|
45
|
+
* @returns Promise containing the data channel (optional) and offer SDP
|
|
46
|
+
*/
|
|
47
|
+
export type OfferFactory = (pc: RTCPeerConnection) => Promise<OfferContext>;
|
|
48
|
+
/**
|
|
49
|
+
* Options for rondevu.offer() - publishing WebRTC offers
|
|
50
|
+
*/
|
|
51
|
+
export interface OfferOptions {
|
|
52
|
+
/** Tags for discovery (e.g., ["chat", "video"]) */
|
|
53
|
+
tags: string[];
|
|
54
|
+
/** Maximum number of concurrent offers to maintain */
|
|
55
|
+
maxOffers: number;
|
|
56
|
+
/** Custom offer creation (defaults to simple data channel) */
|
|
57
|
+
offerFactory?: OfferFactory;
|
|
58
|
+
/** Time-to-live for offers in milliseconds (default: 300000 = 5 minutes) */
|
|
59
|
+
ttl?: number;
|
|
60
|
+
/** Connection durability configuration */
|
|
61
|
+
connectionConfig?: Partial<ConnectionConfig>;
|
|
62
|
+
/** Auto-start filling offers (default: true). Set to false to manually call startFilling() */
|
|
63
|
+
autoStart?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Handle returned by rondevu.offer() for controlling the offer lifecycle
|
|
67
|
+
*/
|
|
68
|
+
export interface OfferHandle {
|
|
69
|
+
/** Stop filling offers and close all connections */
|
|
70
|
+
cancel: () => void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Context provided when a connection is established
|
|
74
|
+
*/
|
|
75
|
+
export interface ConnectionContext {
|
|
76
|
+
/** The underlying RTCPeerConnection */
|
|
77
|
+
pc: RTCPeerConnection;
|
|
78
|
+
/** The data channel for communication */
|
|
79
|
+
dc: RTCDataChannel;
|
|
80
|
+
/** Tags associated with this connection */
|
|
81
|
+
tags: string[];
|
|
82
|
+
/** The offer ID for this connection */
|
|
83
|
+
offerId: string;
|
|
84
|
+
/** Username of the connected peer */
|
|
85
|
+
peerUsername: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Options for rondevu.discover() - discovering available offers
|
|
89
|
+
*/
|
|
90
|
+
export interface DiscoverOptions {
|
|
91
|
+
/** Max results (default: 10) */
|
|
92
|
+
limit?: number;
|
|
93
|
+
/** Offset for pagination (default: 0) */
|
|
94
|
+
offset?: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* A discovered offer from the signaling server
|
|
98
|
+
*/
|
|
99
|
+
export interface DiscoveredOffer {
|
|
100
|
+
/** Unique offer identifier */
|
|
101
|
+
offerId: string;
|
|
102
|
+
/** Username of the offer publisher */
|
|
103
|
+
username: string;
|
|
104
|
+
/** Tags associated with this offer */
|
|
105
|
+
tags: string[];
|
|
106
|
+
/** The WebRTC offer SDP */
|
|
107
|
+
sdp: string;
|
|
108
|
+
/** Timestamp when the offer was created */
|
|
109
|
+
createdAt: number;
|
|
110
|
+
/** Timestamp when the offer expires */
|
|
111
|
+
expiresAt: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Result of a discover() call
|
|
115
|
+
*/
|
|
116
|
+
export interface DiscoverResult {
|
|
117
|
+
/** Array of discovered offers */
|
|
118
|
+
offers: DiscoveredOffer[];
|
|
119
|
+
/** Total count of matching offers */
|
|
120
|
+
count: number;
|
|
121
|
+
/** Limit used in the query */
|
|
122
|
+
limit: number;
|
|
123
|
+
/** Offset used in the query */
|
|
124
|
+
offset: number;
|
|
125
|
+
}
|