@cleocode/lafs-protocol 1.0.0 → 1.2.0
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 +7 -3
- package/dist/schemas/v1/envelope.schema.json +6 -0
- package/dist/src/a2a/bridge.d.ts +129 -0
- package/dist/src/a2a/bridge.js +173 -0
- package/dist/src/a2a/index.d.ts +36 -0
- package/dist/src/a2a/index.js +36 -0
- package/dist/src/circuit-breaker/index.d.ts +121 -0
- package/dist/src/circuit-breaker/index.js +249 -0
- package/dist/src/flagSemantics.d.ts +2 -0
- package/dist/src/flagSemantics.js +7 -6
- package/dist/src/health/index.d.ts +105 -0
- package/dist/src/health/index.js +211 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +6 -0
- package/dist/src/shutdown/index.d.ts +69 -0
- package/dist/src/shutdown/index.js +160 -0
- package/dist/src/types.d.ts +4 -0
- package/lafs.md +187 -0
- package/package.json +3 -2
- package/schemas/v1/envelope.schema.json +6 -0
package/README.md
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
LAFS defines a standard envelope format for structured responses from LLM-powered agents and tools. It complements transport protocols like [MCP](https://modelcontextprotocol.io/) and [A2A](https://github.com/google/A2A) by standardizing what comes back — not how it gets there.
|
|
6
6
|
|
|
7
|
-
**Current version:** 0.
|
|
7
|
+
**Current version:** 1.0.0 | [📚 Documentation](https://codluv.gitbook.io/lafs-protocol/) | [Spec](lafs.md) | [Migration Guides](migrations/)
|
|
8
|
+
|
|
9
|
+
[](https://codluv.gitbook.io/lafs-protocol/)
|
|
10
|
+
[](https://www.npmjs.com/package/@cleocode/lafs-protocol)
|
|
8
11
|
|
|
9
12
|
## What LAFS provides
|
|
10
13
|
|
|
@@ -17,7 +20,7 @@ LAFS defines a standard envelope format for structured responses from LLM-powere
|
|
|
17
20
|
| **Tooling** | `src/` | TypeScript validation, conformance runner, CLI diagnostic tool |
|
|
18
21
|
| **Tests** | `tests/` | 31 tests covering envelope, pagination, strict mode, error handling |
|
|
19
22
|
| **Fixtures** | `fixtures/` | 14 JSON fixtures (valid + invalid) for conformance testing |
|
|
20
|
-
| **Docs** | `docs/` |
|
|
23
|
+
| **Docs** | `docs/` | [GitBook documentation](https://codluv.gitbook.io/lafs-protocol/) with guides, SDK reference, and specs |
|
|
21
24
|
|
|
22
25
|
## Install
|
|
23
26
|
|
|
@@ -64,7 +67,7 @@ npm run typecheck
|
|
|
64
67
|
{
|
|
65
68
|
"$schema": "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
66
69
|
"_meta": {
|
|
67
|
-
"specVersion": "0.
|
|
70
|
+
"specVersion": "1.0.0",
|
|
68
71
|
"schemaVersion": "1.0.0",
|
|
69
72
|
"timestamp": "2026-02-13T00:00:00Z",
|
|
70
73
|
"operation": "example.list",
|
|
@@ -139,6 +142,7 @@ CONTRIBUTING.md # Contributor guidelines, RFC process
|
|
|
139
142
|
|
|
140
143
|
| Version | Phase | Description |
|
|
141
144
|
|---------|-------|-------------|
|
|
145
|
+
| **v1.0.0** | **3** | **Production release: Token budgets, agent discovery, MCP integration, complete SDKs** |
|
|
142
146
|
| v0.5.0 | 2B | Conditional pagination, MVI field selection/expansion, context ledger schema |
|
|
143
147
|
| v0.4.0 | 2A | Optional page/error, extensions, strict/lenient mode, warnings |
|
|
144
148
|
| v0.3.0 | 1 | Strategic positioning, vision alignment, adoption tiers |
|
|
@@ -67,6 +67,12 @@
|
|
|
67
67
|
"type": "integer",
|
|
68
68
|
"minimum": 0
|
|
69
69
|
},
|
|
70
|
+
"sessionId": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"minLength": 1,
|
|
73
|
+
"maxLength": 256,
|
|
74
|
+
"description": "Session identifier for correlating multi-step agent workflows"
|
|
75
|
+
},
|
|
70
76
|
"warnings": {
|
|
71
77
|
"type": "array",
|
|
72
78
|
"items": {
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAFS A2A Bridge
|
|
3
|
+
*
|
|
4
|
+
* Integration with official @a2a-js/sdk for Agent-to-Agent communication.
|
|
5
|
+
* LAFS provides envelope wrapping and token budget support.
|
|
6
|
+
*/
|
|
7
|
+
import { A2AClient } from '@a2a-js/sdk/client';
|
|
8
|
+
import { Artifact, Part, SendMessageResponse, JSONRPCErrorResponse } from '@a2a-js/sdk';
|
|
9
|
+
export interface LafsA2AConfig {
|
|
10
|
+
defaultBudget?: {
|
|
11
|
+
maxTokens?: number;
|
|
12
|
+
maxItems?: number;
|
|
13
|
+
};
|
|
14
|
+
envelopeResponses?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface LafsEnvelope {
|
|
17
|
+
$schema: string;
|
|
18
|
+
_meta: {
|
|
19
|
+
specVersion: string;
|
|
20
|
+
operation: string;
|
|
21
|
+
requestId: string;
|
|
22
|
+
mvi: string;
|
|
23
|
+
_tokenEstimate?: {
|
|
24
|
+
estimated: number;
|
|
25
|
+
budget?: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
success: boolean;
|
|
29
|
+
result: unknown;
|
|
30
|
+
error: null | {
|
|
31
|
+
code: string;
|
|
32
|
+
message: string;
|
|
33
|
+
category: string;
|
|
34
|
+
retryable: boolean;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Wrap A2A client with LAFS envelope support
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import { ClientFactory } from '@a2a-js/sdk/client';
|
|
43
|
+
* import { withLafsEnvelope } from '@lafs/envelope/a2a';
|
|
44
|
+
*
|
|
45
|
+
* const factory = new ClientFactory();
|
|
46
|
+
* const a2aClient = await factory.createFromUrl('http://localhost:4000');
|
|
47
|
+
*
|
|
48
|
+
* const client = withLafsEnvelope(a2aClient, {
|
|
49
|
+
* envelopeResponses: true,
|
|
50
|
+
* defaultBudget: { maxTokens: 4000 }
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* const result = await client.sendMessage({
|
|
54
|
+
* message: { role: 'user', parts: [{ text: 'Hello' }] }
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* // Access LAFS envelope
|
|
58
|
+
* const envelope = result.getLafsEnvelope();
|
|
59
|
+
* console.log(envelope._meta._tokenEstimate);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function withLafsEnvelope(client: A2AClient, config?: LafsA2AConfig): LafsA2AClient;
|
|
63
|
+
export declare class LafsA2AClient {
|
|
64
|
+
private client;
|
|
65
|
+
private config;
|
|
66
|
+
constructor(client: A2AClient, config: LafsA2AConfig);
|
|
67
|
+
sendMessage(params: {
|
|
68
|
+
message: {
|
|
69
|
+
role: 'user' | 'agent';
|
|
70
|
+
parts: Part[];
|
|
71
|
+
};
|
|
72
|
+
budget?: {
|
|
73
|
+
maxTokens?: number;
|
|
74
|
+
maxItems?: number;
|
|
75
|
+
};
|
|
76
|
+
}): Promise<LafsA2AResult>;
|
|
77
|
+
private generateId;
|
|
78
|
+
}
|
|
79
|
+
export declare class LafsA2AResult {
|
|
80
|
+
private result;
|
|
81
|
+
private budget;
|
|
82
|
+
constructor(result: SendMessageResponse, budget: {
|
|
83
|
+
maxTokens?: number;
|
|
84
|
+
maxItems?: number;
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* Get the underlying A2A result
|
|
88
|
+
*/
|
|
89
|
+
getA2AResult(): SendMessageResponse;
|
|
90
|
+
/**
|
|
91
|
+
* Check if result is an error
|
|
92
|
+
*/
|
|
93
|
+
isError(): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Get error details if result is an error
|
|
96
|
+
*/
|
|
97
|
+
getError(): JSONRPCErrorResponse | null;
|
|
98
|
+
/**
|
|
99
|
+
* Extract LAFS envelope from A2A artifact
|
|
100
|
+
*/
|
|
101
|
+
getLafsEnvelope(): LafsEnvelope | null;
|
|
102
|
+
/**
|
|
103
|
+
* Check if result contains LAFS envelope
|
|
104
|
+
*/
|
|
105
|
+
hasLafsEnvelope(): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Get token estimate from envelope
|
|
108
|
+
*/
|
|
109
|
+
getTokenEstimate(): {
|
|
110
|
+
estimated: number;
|
|
111
|
+
budget?: number;
|
|
112
|
+
} | null;
|
|
113
|
+
private isLafsEnvelope;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Create a LAFS artifact for A2A
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const artifact = createLafsArtifact({
|
|
121
|
+
* success: true,
|
|
122
|
+
* result: { data: '...' },
|
|
123
|
+
* meta: { operation: 'analysis.run' }
|
|
124
|
+
* });
|
|
125
|
+
*
|
|
126
|
+
* task.artifacts.push(artifact);
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export declare function createLafsArtifact(envelope: LafsEnvelope): Artifact;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAFS A2A Bridge
|
|
3
|
+
*
|
|
4
|
+
* Integration with official @a2a-js/sdk for Agent-to-Agent communication.
|
|
5
|
+
* LAFS provides envelope wrapping and token budget support.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Wrap A2A client with LAFS envelope support
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { ClientFactory } from '@a2a-js/sdk/client';
|
|
13
|
+
* import { withLafsEnvelope } from '@lafs/envelope/a2a';
|
|
14
|
+
*
|
|
15
|
+
* const factory = new ClientFactory();
|
|
16
|
+
* const a2aClient = await factory.createFromUrl('http://localhost:4000');
|
|
17
|
+
*
|
|
18
|
+
* const client = withLafsEnvelope(a2aClient, {
|
|
19
|
+
* envelopeResponses: true,
|
|
20
|
+
* defaultBudget: { maxTokens: 4000 }
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* const result = await client.sendMessage({
|
|
24
|
+
* message: { role: 'user', parts: [{ text: 'Hello' }] }
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // Access LAFS envelope
|
|
28
|
+
* const envelope = result.getLafsEnvelope();
|
|
29
|
+
* console.log(envelope._meta._tokenEstimate);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function withLafsEnvelope(client, config = {}) {
|
|
33
|
+
return new LafsA2AClient(client, config);
|
|
34
|
+
}
|
|
35
|
+
export class LafsA2AClient {
|
|
36
|
+
client;
|
|
37
|
+
config;
|
|
38
|
+
constructor(client, config) {
|
|
39
|
+
this.client = client;
|
|
40
|
+
this.config = config;
|
|
41
|
+
}
|
|
42
|
+
async sendMessage(params) {
|
|
43
|
+
// Merge budget with defaults
|
|
44
|
+
const budget = {
|
|
45
|
+
...this.config.defaultBudget,
|
|
46
|
+
...params.budget
|
|
47
|
+
};
|
|
48
|
+
// Send via official A2A SDK
|
|
49
|
+
const result = await this.client.sendMessage({
|
|
50
|
+
message: {
|
|
51
|
+
kind: 'message',
|
|
52
|
+
messageId: this.generateId(),
|
|
53
|
+
role: params.message.role,
|
|
54
|
+
parts: params.message.parts
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Wrap result with LAFS envelope support
|
|
58
|
+
return new LafsA2AResult(result, budget);
|
|
59
|
+
}
|
|
60
|
+
generateId() {
|
|
61
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
62
|
+
const r = Math.random() * 16 | 0;
|
|
63
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
64
|
+
return v.toString(16);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export class LafsA2AResult {
|
|
69
|
+
result;
|
|
70
|
+
budget;
|
|
71
|
+
constructor(result, budget) {
|
|
72
|
+
this.result = result;
|
|
73
|
+
this.budget = budget;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get the underlying A2A result
|
|
77
|
+
*/
|
|
78
|
+
getA2AResult() {
|
|
79
|
+
return this.result;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check if result is an error
|
|
83
|
+
*/
|
|
84
|
+
isError() {
|
|
85
|
+
return 'error' in this.result;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get error details if result is an error
|
|
89
|
+
*/
|
|
90
|
+
getError() {
|
|
91
|
+
if (this.isError()) {
|
|
92
|
+
return this.result;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Extract LAFS envelope from A2A artifact
|
|
98
|
+
*/
|
|
99
|
+
getLafsEnvelope() {
|
|
100
|
+
if (this.isError()) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const successResult = this.result;
|
|
104
|
+
// Check if result is a Task
|
|
105
|
+
if (successResult.result?.kind !== 'task') {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const task = successResult.result;
|
|
109
|
+
if (!task.artifacts || task.artifacts.length === 0) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
// Find LAFS envelope in artifacts
|
|
113
|
+
for (const artifact of task.artifacts) {
|
|
114
|
+
for (const part of artifact.parts) {
|
|
115
|
+
if (part.kind === 'data' && this.isLafsEnvelope(part.data)) {
|
|
116
|
+
return part.data;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Check if result contains LAFS envelope
|
|
124
|
+
*/
|
|
125
|
+
hasLafsEnvelope() {
|
|
126
|
+
return this.getLafsEnvelope() !== null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get token estimate from envelope
|
|
130
|
+
*/
|
|
131
|
+
getTokenEstimate() {
|
|
132
|
+
const envelope = this.getLafsEnvelope();
|
|
133
|
+
return envelope?._meta?._tokenEstimate ?? null;
|
|
134
|
+
}
|
|
135
|
+
isLafsEnvelope(data) {
|
|
136
|
+
return (typeof data === 'object' &&
|
|
137
|
+
data !== null &&
|
|
138
|
+
'$schema' in data &&
|
|
139
|
+
'_meta' in data &&
|
|
140
|
+
'success' in data);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create a LAFS artifact for A2A
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const artifact = createLafsArtifact({
|
|
149
|
+
* success: true,
|
|
150
|
+
* result: { data: '...' },
|
|
151
|
+
* meta: { operation: 'analysis.run' }
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* task.artifacts.push(artifact);
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export function createLafsArtifact(envelope) {
|
|
158
|
+
return {
|
|
159
|
+
artifactId: generateId(),
|
|
160
|
+
name: 'lafs_response',
|
|
161
|
+
parts: [{
|
|
162
|
+
kind: 'data',
|
|
163
|
+
data: envelope
|
|
164
|
+
}]
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function generateId() {
|
|
168
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
169
|
+
const r = Math.random() * 16 | 0;
|
|
170
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
171
|
+
return v.toString(16);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAFS Agent-to-Agent (A2A) Integration
|
|
3
|
+
*
|
|
4
|
+
* This module provides integration between LAFS and the official
|
|
5
|
+
* @a2a-js/sdk for Agent-to-Agent communication.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { ClientFactory } from '@a2a-js/sdk/client';
|
|
10
|
+
* import { withLafsEnvelope } from '@cleocode/lafs-protocol/a2a';
|
|
11
|
+
*
|
|
12
|
+
* // Create official A2A client
|
|
13
|
+
* const factory = new ClientFactory();
|
|
14
|
+
* const a2aClient = await factory.createFromUrl('http://agent.example.com');
|
|
15
|
+
*
|
|
16
|
+
* // Wrap with LAFS support
|
|
17
|
+
* const client = withLafsEnvelope(a2aClient, {
|
|
18
|
+
* defaultBudget: { maxTokens: 4000 }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Send message
|
|
22
|
+
* const result = await client.sendMessage({
|
|
23
|
+
* message: {
|
|
24
|
+
* role: 'user',
|
|
25
|
+
* parts: [{ text: 'Analyze data' }]
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Extract LAFS envelope from response
|
|
30
|
+
* const envelope = result.getLafsEnvelope();
|
|
31
|
+
* if (envelope) {
|
|
32
|
+
* console.log(envelope._meta._tokenEstimate);
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export { withLafsEnvelope, LafsA2AClient, LafsA2AResult, createLafsArtifact, type LafsA2AConfig, type LafsEnvelope } from './bridge.js';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAFS Agent-to-Agent (A2A) Integration
|
|
3
|
+
*
|
|
4
|
+
* This module provides integration between LAFS and the official
|
|
5
|
+
* @a2a-js/sdk for Agent-to-Agent communication.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { ClientFactory } from '@a2a-js/sdk/client';
|
|
10
|
+
* import { withLafsEnvelope } from '@cleocode/lafs-protocol/a2a';
|
|
11
|
+
*
|
|
12
|
+
* // Create official A2A client
|
|
13
|
+
* const factory = new ClientFactory();
|
|
14
|
+
* const a2aClient = await factory.createFromUrl('http://agent.example.com');
|
|
15
|
+
*
|
|
16
|
+
* // Wrap with LAFS support
|
|
17
|
+
* const client = withLafsEnvelope(a2aClient, {
|
|
18
|
+
* defaultBudget: { maxTokens: 4000 }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Send message
|
|
22
|
+
* const result = await client.sendMessage({
|
|
23
|
+
* message: {
|
|
24
|
+
* role: 'user',
|
|
25
|
+
* parts: [{ text: 'Analyze data' }]
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Extract LAFS envelope from response
|
|
30
|
+
* const envelope = result.getLafsEnvelope();
|
|
31
|
+
* if (envelope) {
|
|
32
|
+
* console.log(envelope._meta._tokenEstimate);
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export { withLafsEnvelope, LafsA2AClient, LafsA2AResult, createLafsArtifact } from './bridge.js';
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LAFS Circuit Breaker Module
|
|
3
|
+
*
|
|
4
|
+
* Provides circuit breaker pattern for resilient service calls
|
|
5
|
+
*/
|
|
6
|
+
export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
|
|
7
|
+
export interface CircuitBreakerConfig {
|
|
8
|
+
name: string;
|
|
9
|
+
failureThreshold?: number;
|
|
10
|
+
resetTimeout?: number;
|
|
11
|
+
halfOpenMaxCalls?: number;
|
|
12
|
+
successThreshold?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CircuitBreakerMetrics {
|
|
15
|
+
state: CircuitState;
|
|
16
|
+
failures: number;
|
|
17
|
+
successes: number;
|
|
18
|
+
lastFailureTime?: Date;
|
|
19
|
+
consecutiveSuccesses: number;
|
|
20
|
+
totalCalls: number;
|
|
21
|
+
}
|
|
22
|
+
export declare class CircuitBreakerError extends Error {
|
|
23
|
+
constructor(message: string);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Circuit breaker for protecting against cascading failures
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* import { CircuitBreaker } from '@cleocode/lafs-protocol/circuit-breaker';
|
|
31
|
+
*
|
|
32
|
+
* const breaker = new CircuitBreaker({
|
|
33
|
+
* name: 'external-api',
|
|
34
|
+
* failureThreshold: 5,
|
|
35
|
+
* resetTimeout: 30000
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* try {
|
|
39
|
+
* const result = await breaker.execute(async () => {
|
|
40
|
+
* return await externalApi.call();
|
|
41
|
+
* });
|
|
42
|
+
* } catch (error) {
|
|
43
|
+
* if (error instanceof CircuitBreakerError) {
|
|
44
|
+
* console.log('Circuit breaker is open');
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare class CircuitBreaker {
|
|
50
|
+
private config;
|
|
51
|
+
private state;
|
|
52
|
+
private failures;
|
|
53
|
+
private successes;
|
|
54
|
+
private lastFailureTime?;
|
|
55
|
+
private consecutiveSuccesses;
|
|
56
|
+
private totalCalls;
|
|
57
|
+
private halfOpenCalls;
|
|
58
|
+
private resetTimer?;
|
|
59
|
+
constructor(config: CircuitBreakerConfig);
|
|
60
|
+
/**
|
|
61
|
+
* Execute a function with circuit breaker protection
|
|
62
|
+
*/
|
|
63
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
64
|
+
/**
|
|
65
|
+
* Get current circuit breaker state
|
|
66
|
+
*/
|
|
67
|
+
getState(): CircuitState;
|
|
68
|
+
/**
|
|
69
|
+
* Get circuit breaker metrics
|
|
70
|
+
*/
|
|
71
|
+
getMetrics(): CircuitBreakerMetrics;
|
|
72
|
+
/**
|
|
73
|
+
* Manually open the circuit breaker
|
|
74
|
+
*/
|
|
75
|
+
forceOpen(): void;
|
|
76
|
+
/**
|
|
77
|
+
* Manually close the circuit breaker
|
|
78
|
+
*/
|
|
79
|
+
forceClose(): void;
|
|
80
|
+
private onSuccess;
|
|
81
|
+
private onFailure;
|
|
82
|
+
private transitionTo;
|
|
83
|
+
private shouldAttemptReset;
|
|
84
|
+
private scheduleReset;
|
|
85
|
+
private reset;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Circuit breaker registry for managing multiple breakers
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const registry = new CircuitBreakerRegistry();
|
|
93
|
+
*
|
|
94
|
+
* registry.add('payment-api', {
|
|
95
|
+
* failureThreshold: 3,
|
|
96
|
+
* resetTimeout: 60000
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* const paymentBreaker = registry.get('payment-api');
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare class CircuitBreakerRegistry {
|
|
103
|
+
private breakers;
|
|
104
|
+
add(name: string, config: Omit<CircuitBreakerConfig, 'name'>): CircuitBreaker;
|
|
105
|
+
get(name: string): CircuitBreaker | undefined;
|
|
106
|
+
getOrCreate(name: string, config: Omit<CircuitBreakerConfig, 'name'>): CircuitBreaker;
|
|
107
|
+
getAllMetrics(): Record<string, CircuitBreakerMetrics>;
|
|
108
|
+
resetAll(): void;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a circuit breaker middleware for Express
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* app.use('/external-api', circuitBreakerMiddleware({
|
|
116
|
+
* name: 'external-api',
|
|
117
|
+
* failureThreshold: 5
|
|
118
|
+
* }));
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare function circuitBreakerMiddleware(config: CircuitBreakerConfig): (req: any, res: any, next: any) => Promise<void>;
|