a2a-did 0.1.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/LICENSE +21 -0
- package/README.md +180 -0
- package/dist/a2a/constants.d.ts +10 -0
- package/dist/a2a/constants.d.ts.map +1 -0
- package/dist/a2a/constants.js +10 -0
- package/dist/a2a/constants.js.map +1 -0
- package/dist/a2a/index.d.ts +23 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +27 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/a2a/resolution.d.ts +20 -0
- package/dist/a2a/resolution.d.ts.map +1 -0
- package/dist/a2a/resolution.js +55 -0
- package/dist/a2a/resolution.js.map +1 -0
- package/dist/a2a/signing.d.ts +24 -0
- package/dist/a2a/signing.d.ts.map +1 -0
- package/dist/a2a/signing.js +31 -0
- package/dist/a2a/signing.js.map +1 -0
- package/dist/a2a/utils.d.ts +29 -0
- package/dist/a2a/utils.d.ts.map +1 -0
- package/dist/a2a/utils.js +70 -0
- package/dist/a2a/utils.js.map +1 -0
- package/dist/a2a/verification.d.ts +42 -0
- package/dist/a2a/verification.d.ts.map +1 -0
- package/dist/a2a/verification.js +156 -0
- package/dist/a2a/verification.js.map +1 -0
- package/dist/agent.d.ts +99 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +149 -0
- package/dist/agent.js.map +1 -0
- package/dist/did/config-types.d.ts +37 -0
- package/dist/did/config-types.d.ts.map +1 -0
- package/dist/did/config-types.js +6 -0
- package/dist/did/config-types.js.map +1 -0
- package/dist/did/document.d.ts +20 -0
- package/dist/did/document.d.ts.map +1 -0
- package/dist/did/document.js +21 -0
- package/dist/did/document.js.map +1 -0
- package/dist/did/factory.d.ts +31 -0
- package/dist/did/factory.d.ts.map +1 -0
- package/dist/did/factory.js +46 -0
- package/dist/did/factory.js.map +1 -0
- package/dist/did/handlers/ethr-handler.d.ts +62 -0
- package/dist/did/handlers/ethr-handler.d.ts.map +1 -0
- package/dist/did/handlers/ethr-handler.js +184 -0
- package/dist/did/handlers/ethr-handler.js.map +1 -0
- package/dist/did/handlers/web-handler.d.ts +73 -0
- package/dist/did/handlers/web-handler.d.ts.map +1 -0
- package/dist/did/handlers/web-handler.js +170 -0
- package/dist/did/handlers/web-handler.js.map +1 -0
- package/dist/did/index.d.ts +10 -0
- package/dist/did/index.d.ts.map +1 -0
- package/dist/did/index.js +15 -0
- package/dist/did/index.js.map +1 -0
- package/dist/did/resolver.d.ts +85 -0
- package/dist/did/resolver.d.ts.map +1 -0
- package/dist/did/resolver.js +120 -0
- package/dist/did/resolver.js.map +1 -0
- package/dist/did/resolvers/ethr.d.ts +74 -0
- package/dist/did/resolvers/ethr.d.ts.map +1 -0
- package/dist/did/resolvers/ethr.js +67 -0
- package/dist/did/resolvers/ethr.js.map +1 -0
- package/dist/did/resolvers/index.d.ts +8 -0
- package/dist/did/resolvers/index.d.ts.map +1 -0
- package/dist/did/resolvers/index.js +8 -0
- package/dist/did/resolvers/index.js.map +1 -0
- package/dist/did/resolvers/web.d.ts +13 -0
- package/dist/did/resolvers/web.d.ts.map +1 -0
- package/dist/did/resolvers/web.js +97 -0
- package/dist/did/resolvers/web.js.map +1 -0
- package/dist/did/service-loader.d.ts +15 -0
- package/dist/did/service-loader.d.ts.map +1 -0
- package/dist/did/service-loader.js +20 -0
- package/dist/did/service-loader.js.map +1 -0
- package/dist/did/service.d.ts +99 -0
- package/dist/did/service.d.ts.map +1 -0
- package/dist/did/service.js +75 -0
- package/dist/did/service.js.map +1 -0
- package/dist/did/signing.d.ts +19 -0
- package/dist/did/signing.d.ts.map +1 -0
- package/dist/did/signing.js +37 -0
- package/dist/did/signing.js.map +1 -0
- package/dist/did/types.d.ts +134 -0
- package/dist/did/types.d.ts.map +1 -0
- package/dist/did/types.js +2 -0
- package/dist/did/types.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 a2a-did contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# a2a-did
|
|
2
|
+
|
|
3
|
+
> DID-based authentication for A2A Protocol - Sign and verify agent messages with did:web and did:ethr
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/a2a-did)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Implementation Notes
|
|
9
|
+
|
|
10
|
+
**This is an experimental v0.1.0 release** focused on basic functionality.
|
|
11
|
+
|
|
12
|
+
For production use, consider implementing additional security measures appropriate to your use case:
|
|
13
|
+
- **Key Management**: This library generates keys in memory. Consider integrating with KMS/HSM based on your security requirements.
|
|
14
|
+
- **DID Resolution**: Implement domain allowlisting if your deployment requires SSRF protection.
|
|
15
|
+
- **Message Replay**: Add timestamps/nonces to messages in your application logic.
|
|
16
|
+
|
|
17
|
+
See [SECURITY.md](./SECURITY.md) for detailed security considerations.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
**a2a-did** provides decentralized identity (DID) authentication for the A2A Protocol, enabling cryptographically verifiable agent-to-agent communication without centralized registries.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- ✅ **DID Identity Management** - Create and resolve DIDs (did:web, did:ethr)
|
|
26
|
+
- ✅ **Message Signing** - Sign A2A messages with DID private keys (ES256K/JWS)
|
|
27
|
+
- ✅ **Signature Verification** - Verify message authenticity with DID public keys
|
|
28
|
+
- ✅ **Zero Pre-registration** - No central registry required
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install a2a-did
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### 1. Create a DID Identity
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { createAgentDIDService } from 'a2a-did';
|
|
42
|
+
|
|
43
|
+
// Create did:web identity (HTTPS-based)
|
|
44
|
+
const service = await createAgentDIDService(['web']);
|
|
45
|
+
const identity = await service.createIdentity({
|
|
46
|
+
method: 'web',
|
|
47
|
+
agentId: 'my-agent',
|
|
48
|
+
config: {
|
|
49
|
+
type: 'web',
|
|
50
|
+
domain: 'example.com',
|
|
51
|
+
port: 443
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
console.log(identity.did);
|
|
56
|
+
// → did:web:example.com%3A443:agents:my-agent
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Sign A2A Messages
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { signA2AMessage } from 'a2a-did';
|
|
63
|
+
|
|
64
|
+
// A2A Protocol message
|
|
65
|
+
const message = {
|
|
66
|
+
jsonrpc: '2.0',
|
|
67
|
+
method: 'message/send',
|
|
68
|
+
params: {
|
|
69
|
+
message: {
|
|
70
|
+
kind: 'message',
|
|
71
|
+
messageId: 'msg-123',
|
|
72
|
+
role: 'user',
|
|
73
|
+
parts: [{ kind: 'text', text: 'Hello' }]
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
id: 1
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Sign with DID
|
|
80
|
+
const signature = await signA2AMessage(message, identity);
|
|
81
|
+
|
|
82
|
+
// Send signed request
|
|
83
|
+
const signedRequest = { ...message, signature };
|
|
84
|
+
await fetch('https://agent.example.com/a2a', {
|
|
85
|
+
method: 'POST',
|
|
86
|
+
body: JSON.stringify(signedRequest)
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 3. Verify Signatures
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { verifySignedA2ARequest } from 'a2a-did';
|
|
94
|
+
|
|
95
|
+
app.post('/a2a', async (req, res) => {
|
|
96
|
+
if (req.body.signature) {
|
|
97
|
+
const result = await verifySignedA2ARequest(req.body);
|
|
98
|
+
|
|
99
|
+
if (!result.valid) {
|
|
100
|
+
return res.json({
|
|
101
|
+
jsonrpc: '2.0',
|
|
102
|
+
error: { code: -32600, message: 'Invalid signature' },
|
|
103
|
+
id: req.body.id
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log(`Authenticated: ${result.senderDid}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Process message...
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## API Reference
|
|
115
|
+
|
|
116
|
+
### Identity Management
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// Create DID service
|
|
120
|
+
createAgentDIDService(methods: Array<'web' | 'ethr'>): Promise<AgentDIDService>
|
|
121
|
+
|
|
122
|
+
// Create identity
|
|
123
|
+
service.createIdentity(options: {
|
|
124
|
+
method: 'web' | 'ethr',
|
|
125
|
+
agentId: string,
|
|
126
|
+
config: WebConfig | EthrConfig
|
|
127
|
+
}): Promise<DIDIdentity>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Message Signing
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Sign message
|
|
134
|
+
signA2AMessage(payload: object, identity: DIDIdentity): Promise<string>
|
|
135
|
+
|
|
136
|
+
// Verify signature
|
|
137
|
+
verifySignedA2ARequest(request: object): Promise<{
|
|
138
|
+
valid: boolean;
|
|
139
|
+
senderDid?: string;
|
|
140
|
+
error?: string;
|
|
141
|
+
}>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Agent Resolution
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Resolve DID → A2A endpoint
|
|
148
|
+
resolveA2AEndpoint(did: string): Promise<string>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## DID Methods
|
|
152
|
+
|
|
153
|
+
### did:web
|
|
154
|
+
|
|
155
|
+
- **Trust model**: HTTPS/TLS (same as web PKI)
|
|
156
|
+
- **Setup**: Simple (HTTPS server only)
|
|
157
|
+
- **Use case**: Corporate agents, fixed endpoints
|
|
158
|
+
|
|
159
|
+
### did:ethr
|
|
160
|
+
|
|
161
|
+
- **Trust model**: Ethereum blockchain
|
|
162
|
+
- **Setup**: Requires RPC endpoint
|
|
163
|
+
- **Use case**: Dynamic agents, cross-domain
|
|
164
|
+
|
|
165
|
+
## Security Notes
|
|
166
|
+
|
|
167
|
+
⚠️ **Important**: This library provides authentication (identity verification) only. You must implement:
|
|
168
|
+
|
|
169
|
+
- **Replay protection**: Add `iat`/`exp`/`jti` to prevent message replay
|
|
170
|
+
- **Authorization**: Access control policies for your agents
|
|
171
|
+
- **Rate limiting**: Protection against DoS attacks
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT
|
|
176
|
+
|
|
177
|
+
## Related Projects
|
|
178
|
+
|
|
179
|
+
- [A2A Protocol](https://github.com/a2aproject/A2A) - Agent-to-Agent Communication Protocol
|
|
180
|
+
- [W3C DID Core](https://www.w3.org/TR/did-core/) - Decentralized Identifiers specification
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Protocol Constants
|
|
3
|
+
* @module a2a/constants
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Service type for Agent Card URL in DID Document
|
|
7
|
+
* Use this constant to ensure consistency across the codebase
|
|
8
|
+
*/
|
|
9
|
+
export declare const A2A_AGENT_CARD_SERVICE_TYPE: "A2AAgentCard";
|
|
10
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/a2a/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAG,cAAuB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Protocol Constants
|
|
3
|
+
* @module a2a/constants
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Service type for Agent Card URL in DID Document
|
|
7
|
+
* Use this constant to ensure consistency across the codebase
|
|
8
|
+
*/
|
|
9
|
+
export const A2A_AGENT_CARD_SERVICE_TYPE = 'A2AAgentCard';
|
|
10
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/a2a/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,cAAuB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Integration Module
|
|
3
|
+
*
|
|
4
|
+
* DID-based authentication and verification for A2A Protocol
|
|
5
|
+
*
|
|
6
|
+
* This module provides:
|
|
7
|
+
* - DID signature creation for A2A messages (signing.ts)
|
|
8
|
+
* - DID signature verification for A2A messages (verification.ts)
|
|
9
|
+
* - Agent Card verification (verification.ts)
|
|
10
|
+
* - DID-to-A2A endpoint resolution (resolution.ts)
|
|
11
|
+
*
|
|
12
|
+
* What this module does NOT provide:
|
|
13
|
+
* - A2A communication (use @a2a-js/sdk)
|
|
14
|
+
* - A2A server implementation (see packages/api)
|
|
15
|
+
* - Message type definitions (use @a2a-js/sdk types)
|
|
16
|
+
*
|
|
17
|
+
* @module a2a
|
|
18
|
+
*/
|
|
19
|
+
export * from './constants.js';
|
|
20
|
+
export * from './resolution.js';
|
|
21
|
+
export * from './verification.js';
|
|
22
|
+
export * from './signing.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/a2a/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,cAAc,gBAAgB,CAAC;AAG/B,cAAc,iBAAiB,CAAC;AAGhC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Integration Module
|
|
3
|
+
*
|
|
4
|
+
* DID-based authentication and verification for A2A Protocol
|
|
5
|
+
*
|
|
6
|
+
* This module provides:
|
|
7
|
+
* - DID signature creation for A2A messages (signing.ts)
|
|
8
|
+
* - DID signature verification for A2A messages (verification.ts)
|
|
9
|
+
* - Agent Card verification (verification.ts)
|
|
10
|
+
* - DID-to-A2A endpoint resolution (resolution.ts)
|
|
11
|
+
*
|
|
12
|
+
* What this module does NOT provide:
|
|
13
|
+
* - A2A communication (use @a2a-js/sdk)
|
|
14
|
+
* - A2A server implementation (see packages/api)
|
|
15
|
+
* - Message type definitions (use @a2a-js/sdk types)
|
|
16
|
+
*
|
|
17
|
+
* @module a2a
|
|
18
|
+
*/
|
|
19
|
+
// Constants
|
|
20
|
+
export * from './constants.js';
|
|
21
|
+
// Resolution functions
|
|
22
|
+
export * from './resolution.js';
|
|
23
|
+
// Verification functions
|
|
24
|
+
export * from './verification.js';
|
|
25
|
+
// Signing functions
|
|
26
|
+
export * from './signing.js';
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/a2a/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,YAAY;AACZ,cAAc,gBAAgB,CAAC;AAE/B,uBAAuB;AACvB,cAAc,iBAAiB,CAAC;AAEhC,yBAAyB;AACzB,cAAc,mBAAmB,CAAC;AAElC,oBAAoB;AACpB,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DIDDocument } from '../did/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extract Agent Card URL from DID Document
|
|
4
|
+
* @param document - The DID Document
|
|
5
|
+
* @returns The Agent Card URL, or undefined if not found
|
|
6
|
+
*/
|
|
7
|
+
export declare function extractAgentCardUrl(document: DIDDocument): string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a DID and get its A2A endpoint
|
|
10
|
+
* Follows A2A Protocol 0.3.0: DID → Agent Card URL → Agent Card → A2A endpoint
|
|
11
|
+
*
|
|
12
|
+
* IMPORTANT: For did:ethr, you must call configureResolver() before using this function.
|
|
13
|
+
* See packages/core/src/did/resolver.ts for configuration details.
|
|
14
|
+
*
|
|
15
|
+
* @param did - The DID to resolve
|
|
16
|
+
* @returns The A2A endpoint URL from Agent Card
|
|
17
|
+
* @throws Error if DID cannot be resolved, has no Agent Card, or Agent Card has no url
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveA2AEndpoint(did: string): Promise<string>;
|
|
20
|
+
//# sourceMappingURL=resolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolution.d.ts","sourceRoot":"","sources":["../../src/a2a/resolution.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,iBAAiB,CAAC;AAmBpE;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAQ7E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BrE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Resolution Functions
|
|
3
|
+
* DID Document から Agent Card URL や A2A エンドポイントを解決
|
|
4
|
+
* @module a2a/resolution
|
|
5
|
+
*/
|
|
6
|
+
import { resolveDID } from '../did/resolver.js';
|
|
7
|
+
import { A2A_AGENT_CARD_SERVICE_TYPE } from './constants.js';
|
|
8
|
+
import { fetchUri } from './utils.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extract Agent Card URL from DID Document
|
|
11
|
+
* @param document - The DID Document
|
|
12
|
+
* @returns The Agent Card URL, or undefined if not found
|
|
13
|
+
*/
|
|
14
|
+
export function extractAgentCardUrl(document) {
|
|
15
|
+
const service = document.service?.find((s) => s.type === A2A_AGENT_CARD_SERVICE_TYPE);
|
|
16
|
+
if (!service)
|
|
17
|
+
return undefined;
|
|
18
|
+
return typeof service.serviceEndpoint === 'string'
|
|
19
|
+
? service.serviceEndpoint
|
|
20
|
+
: undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a DID and get its A2A endpoint
|
|
24
|
+
* Follows A2A Protocol 0.3.0: DID → Agent Card URL → Agent Card → A2A endpoint
|
|
25
|
+
*
|
|
26
|
+
* IMPORTANT: For did:ethr, you must call configureResolver() before using this function.
|
|
27
|
+
* See packages/core/src/did/resolver.ts for configuration details.
|
|
28
|
+
*
|
|
29
|
+
* @param did - The DID to resolve
|
|
30
|
+
* @returns The A2A endpoint URL from Agent Card
|
|
31
|
+
* @throws Error if DID cannot be resolved, has no Agent Card, or Agent Card has no url
|
|
32
|
+
*/
|
|
33
|
+
export async function resolveA2AEndpoint(did) {
|
|
34
|
+
// Step 1: Resolve DID to get Agent Card URL
|
|
35
|
+
const document = await resolveDID(did);
|
|
36
|
+
if (!document) {
|
|
37
|
+
throw new Error(`Failed to resolve DID: ${did}`);
|
|
38
|
+
}
|
|
39
|
+
const agentCardUrl = extractAgentCardUrl(document);
|
|
40
|
+
if (!agentCardUrl) {
|
|
41
|
+
throw new Error(`No Agent Card URL found in DID Document: ${did}`);
|
|
42
|
+
}
|
|
43
|
+
// Step 2: Fetch Agent Card with cryptographic verification (supports http://, https://, ipfs://)
|
|
44
|
+
const response = await fetchUri(agentCardUrl);
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
const agentCard = (await response.json());
|
|
49
|
+
// Step 3: Extract A2A endpoint from Agent Card
|
|
50
|
+
if (!agentCard.url || typeof agentCard.url !== 'string') {
|
|
51
|
+
throw new Error(`Agent Card has no valid url field: ${agentCardUrl}`);
|
|
52
|
+
}
|
|
53
|
+
return agentCard.url;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolution.js","sourceRoot":"","sources":["../../src/a2a/resolution.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAiBtC;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAqB;IACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CACpC,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,2BAA2B,CAC/D,CAAC;IACF,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,OAAO,OAAO,CAAC,eAAe,KAAK,QAAQ;QAChD,CAAC,CAAC,OAAO,CAAC,eAAe;QACzB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,4CAA4C;IAC5C,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,YAAY,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,4CAA4C,GAAG,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,iGAAiG;IACjG,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,mCAAmC,YAAY,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,SAAS,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAoB,CAAC;IAE7D,+CAA+C;IAC/C,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,OAAO,SAAS,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,sCAAsC,YAAY,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,SAAS,CAAC,GAAG,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DIDIdentity } from '../did/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sign an A2A message or request with the sender's DID identity
|
|
4
|
+
* Creates a JWS signature using the DID private key
|
|
5
|
+
*
|
|
6
|
+
* @param payload - The message or request to sign (any A2A JSON-RPC message)
|
|
7
|
+
* @param signer - The sender's DID identity (contains private key)
|
|
8
|
+
* @returns The JWS signature (compact format)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const identity = await createIdentity(...);
|
|
13
|
+
* const message = {
|
|
14
|
+
* jsonrpc: '2.0',
|
|
15
|
+
* method: 'message/send',
|
|
16
|
+
* params: { ... },
|
|
17
|
+
* id: 1
|
|
18
|
+
* };
|
|
19
|
+
* const signature = await signA2AMessage(message, identity);
|
|
20
|
+
* const signedRequest = { ...message, signature };
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function signA2AMessage(payload: Record<string, unknown>, signer: DIDIdentity): Promise<string>;
|
|
24
|
+
//# sourceMappingURL=signing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../src/a2a/signing.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,CAMjB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Signing Functions
|
|
3
|
+
* DID Identity を使った A2A メッセージへの署名
|
|
4
|
+
* @module a2a/signing
|
|
5
|
+
*/
|
|
6
|
+
import { createJWS } from 'did-jwt';
|
|
7
|
+
/**
|
|
8
|
+
* Sign an A2A message or request with the sender's DID identity
|
|
9
|
+
* Creates a JWS signature using the DID private key
|
|
10
|
+
*
|
|
11
|
+
* @param payload - The message or request to sign (any A2A JSON-RPC message)
|
|
12
|
+
* @param signer - The sender's DID identity (contains private key)
|
|
13
|
+
* @returns The JWS signature (compact format)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const identity = await createIdentity(...);
|
|
18
|
+
* const message = {
|
|
19
|
+
* jsonrpc: '2.0',
|
|
20
|
+
* method: 'message/send',
|
|
21
|
+
* params: { ... },
|
|
22
|
+
* id: 1
|
|
23
|
+
* };
|
|
24
|
+
* const signature = await signA2AMessage(message, identity);
|
|
25
|
+
* const signedRequest = { ...message, signature };
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export async function signA2AMessage(payload, signer) {
|
|
29
|
+
return createJWS(payload, signer.signer, { alg: 'ES256K', kid: signer.keyId });
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../src/a2a/signing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgC,EAChC,MAAmB;IAEnB,OAAO,SAAS,CACd,OAAO,EACP,MAAM,CAAC,MAAM,EACb,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,EAAE,CACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64URL encode a string
|
|
3
|
+
*/
|
|
4
|
+
export declare function base64UrlEncode(str: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Decode base64url to JSON
|
|
7
|
+
*/
|
|
8
|
+
export declare function decodeBase64UrlJson(str: string): Record<string, unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Normalize JSON for comparison
|
|
11
|
+
*/
|
|
12
|
+
export declare function normalizeJson(value: unknown): unknown;
|
|
13
|
+
/**
|
|
14
|
+
* Compare JSON objects for equality
|
|
15
|
+
*/
|
|
16
|
+
export declare function jsonEquals(a: unknown, b: unknown): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Fetch content from URI with cryptographic verification for IPFS content
|
|
19
|
+
*
|
|
20
|
+
* - For ipfs:// and ipns:// URIs: Uses @helia/verified-fetch for trustless content retrieval
|
|
21
|
+
* with CID verification, multiple gateway fallbacks, and tamper detection
|
|
22
|
+
* - For http:// and https:// URIs: Uses standard fetch (assumes TLS provides sufficient security)
|
|
23
|
+
*
|
|
24
|
+
* @param uri - URI to fetch (http://, https://, ipfs://, or ipns://)
|
|
25
|
+
* @returns Fetch response
|
|
26
|
+
* @throws Error if URI scheme is unsupported or verification fails
|
|
27
|
+
*/
|
|
28
|
+
export declare function fetchUri(uri: string): Promise<Response>;
|
|
29
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/a2a/utils.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAcrD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAU7D"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Utility Functions
|
|
3
|
+
* @module a2a/utils
|
|
4
|
+
*/
|
|
5
|
+
import * as u8a from 'uint8arrays';
|
|
6
|
+
import { verifiedFetch } from '@helia/verified-fetch';
|
|
7
|
+
const textEncoder = new TextEncoder();
|
|
8
|
+
const textDecoder = new TextDecoder();
|
|
9
|
+
/**
|
|
10
|
+
* Base64URL encode a string
|
|
11
|
+
*/
|
|
12
|
+
export function base64UrlEncode(str) {
|
|
13
|
+
return u8a.toString(textEncoder.encode(str), 'base64url');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Decode base64url to JSON
|
|
17
|
+
*/
|
|
18
|
+
export function decodeBase64UrlJson(str) {
|
|
19
|
+
const json = textDecoder.decode(u8a.fromString(str, 'base64url'));
|
|
20
|
+
return JSON.parse(json);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Normalize JSON for comparison
|
|
24
|
+
*/
|
|
25
|
+
export function normalizeJson(value) {
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
return value.map(normalizeJson);
|
|
28
|
+
}
|
|
29
|
+
if (value && typeof value === 'object') {
|
|
30
|
+
const record = value;
|
|
31
|
+
return Object.keys(record)
|
|
32
|
+
.sort()
|
|
33
|
+
.reduce((acc, key) => {
|
|
34
|
+
acc[key] = normalizeJson(record[key]);
|
|
35
|
+
return acc;
|
|
36
|
+
}, {});
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Compare JSON objects for equality
|
|
42
|
+
*/
|
|
43
|
+
export function jsonEquals(a, b) {
|
|
44
|
+
return JSON.stringify(normalizeJson(a)) === JSON.stringify(normalizeJson(b));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Fetch content from URI with cryptographic verification for IPFS content
|
|
48
|
+
*
|
|
49
|
+
* - For ipfs:// and ipns:// URIs: Uses @helia/verified-fetch for trustless content retrieval
|
|
50
|
+
* with CID verification, multiple gateway fallbacks, and tamper detection
|
|
51
|
+
* - For http:// and https:// URIs: Uses standard fetch (assumes TLS provides sufficient security)
|
|
52
|
+
*
|
|
53
|
+
* @param uri - URI to fetch (http://, https://, ipfs://, or ipns://)
|
|
54
|
+
* @returns Fetch response
|
|
55
|
+
* @throws Error if URI scheme is unsupported or verification fails
|
|
56
|
+
*/
|
|
57
|
+
export async function fetchUri(uri) {
|
|
58
|
+
if (uri.startsWith('ipfs://') || uri.startsWith('ipns://')) {
|
|
59
|
+
// Use verified fetch for IPFS/IPNS content (cryptographic verification + multiple gateways)
|
|
60
|
+
return verifiedFetch(uri);
|
|
61
|
+
}
|
|
62
|
+
else if (uri.startsWith('http://') || uri.startsWith('https://')) {
|
|
63
|
+
// Use standard fetch for HTTP/HTTPS (TLS provides transport security)
|
|
64
|
+
return fetch(uri);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
throw new Error(`Unsupported URI scheme: ${uri}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/a2a/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AACtC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;IAClE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;aACvB,IAAI,EAAE;aACN,MAAM,CAA0B,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,GAAG,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAAE,CAAC,CAAC;IACX,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,CAAU,EAAE,CAAU;IAC/C,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW;IACxC,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3D,4FAA4F;QAC5F,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;SAAM,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACnE,sEAAsE;QACtE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentCard verification result
|
|
3
|
+
*/
|
|
4
|
+
export interface AgentCardVerificationResult {
|
|
5
|
+
verified: boolean;
|
|
6
|
+
signerDid?: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A2A Message Signature Verification Result
|
|
11
|
+
*/
|
|
12
|
+
export interface MessageSignatureVerificationResult {
|
|
13
|
+
valid: boolean;
|
|
14
|
+
senderDid?: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Verify AgentCard signature
|
|
19
|
+
* @param agentCardUrl - URL to fetch AgentCard from (supports http://, https://, ipfs://)
|
|
20
|
+
* @returns Verification result with signer DID if successful
|
|
21
|
+
*/
|
|
22
|
+
export declare function verifyAgentCard(agentCardUrl: string): Promise<AgentCardVerificationResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Verify A2A message JWS signature using DID public key
|
|
25
|
+
* Follows A2A Protocol 0.3.0: Verifies Agent Card signature first, then message signature
|
|
26
|
+
*
|
|
27
|
+
* @param jws - The JWS signature string (compact format)
|
|
28
|
+
* @returns Verification result with sender DID if successful
|
|
29
|
+
*/
|
|
30
|
+
export declare function verifyA2AMessageSignature(jws: string): Promise<MessageSignatureVerificationResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Verify A2A request with signature validation and payload integrity check
|
|
33
|
+
* This is a convenience function for API servers to validate incoming signed requests
|
|
34
|
+
*
|
|
35
|
+
* @param request - The signed A2A request (JSON-RPC with signature field)
|
|
36
|
+
* @returns Verification result with sender DID if successful
|
|
37
|
+
*/
|
|
38
|
+
export declare function verifySignedA2ARequest(request: {
|
|
39
|
+
signature?: string;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}): Promise<MessageSignatureVerificationResult>;
|
|
42
|
+
//# sourceMappingURL=verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../src/a2a/verification.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,kCAAkC;IACjD,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,2BAA2B,CAAC,CAyDtC;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,kCAAkC,CAAC,CA8D7C;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GACtD,OAAO,CAAC,kCAAkC,CAAC,CA4B7C"}
|