@framers/agentos-ext-anchor-providers 1.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/CHANGELOG.md +16 -0
- package/README.md +353 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/EthereumProvider.d.ts +36 -0
- package/dist/providers/EthereumProvider.d.ts.map +1 -0
- package/dist/providers/EthereumProvider.js +66 -0
- package/dist/providers/EthereumProvider.js.map +1 -0
- package/dist/providers/OpenTimestampsProvider.d.ts +28 -0
- package/dist/providers/OpenTimestampsProvider.d.ts.map +1 -0
- package/dist/providers/OpenTimestampsProvider.js +72 -0
- package/dist/providers/OpenTimestampsProvider.js.map +1 -0
- package/dist/providers/RekorProvider.d.ts +28 -0
- package/dist/providers/RekorProvider.d.ts.map +1 -0
- package/dist/providers/RekorProvider.js +68 -0
- package/dist/providers/RekorProvider.js.map +1 -0
- package/dist/providers/SolanaProvider.d.ts +62 -0
- package/dist/providers/SolanaProvider.d.ts.map +1 -0
- package/dist/providers/SolanaProvider.js +256 -0
- package/dist/providers/SolanaProvider.js.map +1 -0
- package/dist/providers/WormSnapshotProvider.d.ts +35 -0
- package/dist/providers/WormSnapshotProvider.d.ts.map +1 -0
- package/dist/providers/WormSnapshotProvider.js +64 -0
- package/dist/providers/WormSnapshotProvider.js.map +1 -0
- package/dist/register.d.ts +31 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +47 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/http-client.d.ts +23 -0
- package/dist/utils/http-client.d.ts.map +1 -0
- package/dist/utils/http-client.js +53 -0
- package/dist/utils/http-client.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/serialization.d.ts +16 -0
- package/dist/utils/serialization.d.ts.map +1 -0
- package/dist/utils/serialization.js +30 -0
- package/dist/utils/serialization.js.map +1 -0
- package/manifest.json +100 -0
- package/package.json +103 -0
- package/src/index.ts +59 -0
- package/src/providers/EthereumProvider.ts +87 -0
- package/src/providers/OpenTimestampsProvider.ts +86 -0
- package/src/providers/RekorProvider.ts +82 -0
- package/src/providers/SolanaProvider.ts +439 -0
- package/src/providers/WormSnapshotProvider.ts +84 -0
- package/src/register.ts +69 -0
- package/src/types.ts +27 -0
- package/src/utils/http-client.ts +75 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/serialization.ts +33 -0
- package/test/integration.spec.ts +175 -0
- package/test/providers.spec.ts +163 -0
- package/test/register.spec.ts +69 -0
- package/test/types.spec.ts +55 -0
- package/test/utils.spec.ts +225 -0
- package/tsconfig.json +21 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# @framers/agentos-ext-anchor-providers
|
|
2
|
+
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`e6a2eb6`](https://github.com/framersai/agentos-extensions/commit/e6a2eb61145c5715df63668b795fe90720a3c7c1) Thanks [@jddunn](https://github.com/jddunn)! - Initial release of AgentOS extension packages.
|
|
8
|
+
|
|
9
|
+
- Auth: JWT authentication and subscription management
|
|
10
|
+
- Anchor Providers: Solana on-chain provenance anchoring
|
|
11
|
+
- Wunderland Tip Ingestion: Tip content processing pipeline
|
|
12
|
+
- Web Search: Search, research aggregation, and fact-checking
|
|
13
|
+
- Web Browser: Browser automation and content extraction
|
|
14
|
+
- Telegram Integration: Telegram Bot API integration
|
|
15
|
+
- Telegram Bot: Telegram bot communications handler
|
|
16
|
+
- CLI Executor: Shell command execution and file management
|
package/README.md
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# @framers/agentos-ext-anchor-providers
|
|
2
|
+
|
|
3
|
+
External anchor providers for the [AgentOS](https://github.com/framersai/agentos) provenance system. Extends the built-in signed hash chain with external tamper-evidence backends — WORM storage, transparency logs, and blockchain timestamping.
|
|
4
|
+
|
|
5
|
+
## Proof Levels
|
|
6
|
+
|
|
7
|
+
Each provider advertises a proof level (ascending trust):
|
|
8
|
+
|
|
9
|
+
| Level | Meaning | Provider |
|
|
10
|
+
|-------|---------|----------|
|
|
11
|
+
| `verifiable` | Local signed hash chain only | Built-in (`NoneProvider`) |
|
|
12
|
+
| `externally-archived` | Immutable external archive with retention policy | `WormSnapshotProvider` |
|
|
13
|
+
| `publicly-auditable` | Append-only public transparency log | `RekorProvider` |
|
|
14
|
+
| `publicly-timestamped` | Blockchain-anchored timestamp proof | `OpenTimestampsProvider`, `EthereumProvider`, `SolanaProvider` |
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @framers/agentos-ext-anchor-providers
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Install the peer dependency for your chosen provider:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# For WORM Snapshot (S3 Object Lock)
|
|
26
|
+
pnpm add @aws-sdk/client-s3
|
|
27
|
+
|
|
28
|
+
# For Rekor (Sigstore Transparency Log)
|
|
29
|
+
pnpm add sigstore
|
|
30
|
+
|
|
31
|
+
# For OpenTimestamps (Bitcoin)
|
|
32
|
+
pnpm add opentimestamps
|
|
33
|
+
|
|
34
|
+
# For Ethereum (On-Chain Anchor)
|
|
35
|
+
pnpm add ethers
|
|
36
|
+
|
|
37
|
+
# For Solana (On-Chain Anchor)
|
|
38
|
+
pnpm add @solana/web3.js
|
|
39
|
+
|
|
40
|
+
# Optional (only if using base58 secret keys)
|
|
41
|
+
pnpm add bs58
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
### Option 1: Config-Driven (via Registry)
|
|
47
|
+
|
|
48
|
+
Register all providers once at startup, then use the core factory:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { registerExtensionProviders } from '@framers/agentos-ext-anchor-providers';
|
|
52
|
+
import { createAnchorProvider } from '@framers/agentos';
|
|
53
|
+
|
|
54
|
+
// Register once at startup
|
|
55
|
+
registerExtensionProviders();
|
|
56
|
+
|
|
57
|
+
// Create provider from config
|
|
58
|
+
const provider = createAnchorProvider({
|
|
59
|
+
type: 'rekor',
|
|
60
|
+
options: { serverUrl: 'https://rekor.sigstore.dev' },
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Option 2: Direct Construction
|
|
65
|
+
|
|
66
|
+
Import and instantiate providers directly:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
|
|
70
|
+
|
|
71
|
+
const provider = new RekorProvider({
|
|
72
|
+
serverUrl: 'https://rekor.sigstore.dev',
|
|
73
|
+
timeoutMs: 15000,
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Using with AnchorManager
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { AnchorManager, profiles } from '@framers/agentos';
|
|
81
|
+
import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
|
|
82
|
+
|
|
83
|
+
const provider = new RekorProvider();
|
|
84
|
+
const config = profiles.sealedAutonomous();
|
|
85
|
+
|
|
86
|
+
const anchorManager = new AnchorManager(
|
|
87
|
+
storageAdapter,
|
|
88
|
+
ledger,
|
|
89
|
+
keyManager,
|
|
90
|
+
config,
|
|
91
|
+
'', // table prefix
|
|
92
|
+
provider, // external anchor provider
|
|
93
|
+
);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Providers
|
|
97
|
+
|
|
98
|
+
### WORM Snapshot Provider (S3 Object Lock)
|
|
99
|
+
|
|
100
|
+
Archives anchor records to S3 with Object Lock retention. Provides compliance-grade immutability — objects cannot be deleted or overwritten during the retention period.
|
|
101
|
+
|
|
102
|
+
**Proof level:** `externally-archived`
|
|
103
|
+
**Peer dependency:** `@aws-sdk/client-s3`
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { WormSnapshotProvider } from '@framers/agentos-ext-anchor-providers';
|
|
107
|
+
|
|
108
|
+
const provider = new WormSnapshotProvider({
|
|
109
|
+
bucket: 'my-provenance-bucket', // Required: S3 bucket with Object Lock enabled
|
|
110
|
+
region: 'us-east-1', // Required: AWS region
|
|
111
|
+
keyPrefix: 'provenance/anchors/', // Default: 'provenance/anchors/'
|
|
112
|
+
retentionDays: 365, // Default: 365
|
|
113
|
+
retentionMode: 'COMPLIANCE', // 'GOVERNANCE' (default) or 'COMPLIANCE'
|
|
114
|
+
timeoutMs: 30000, // Default: 30000
|
|
115
|
+
retries: 3, // Default: 3
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Rekor Provider (Sigstore Transparency Log)
|
|
120
|
+
|
|
121
|
+
Publishes anchor hashes to [Sigstore Rekor](https://rekor.sigstore.dev), a publicly auditable append-only transparency log. Entries are permanently recorded and anyone can verify inclusion.
|
|
122
|
+
|
|
123
|
+
**Proof level:** `publicly-auditable`
|
|
124
|
+
**Peer dependency:** `sigstore`
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
|
|
128
|
+
|
|
129
|
+
const provider = new RekorProvider({
|
|
130
|
+
serverUrl: 'https://rekor.sigstore.dev', // Default: public Rekor instance
|
|
131
|
+
timeoutMs: 30000,
|
|
132
|
+
retries: 3,
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### OpenTimestamps Provider (Bitcoin)
|
|
137
|
+
|
|
138
|
+
Creates [OpenTimestamps](https://opentimestamps.org) proofs anchored to the Bitcoin blockchain. Proofs are initially pending and confirm after a Bitcoin block includes the calendar commitment (typically 1-2 hours).
|
|
139
|
+
|
|
140
|
+
**Proof level:** `publicly-timestamped`
|
|
141
|
+
**Peer dependency:** `opentimestamps`
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { OpenTimestampsProvider } from '@framers/agentos-ext-anchor-providers';
|
|
145
|
+
|
|
146
|
+
const provider = new OpenTimestampsProvider({
|
|
147
|
+
calendarUrls: [ // Default: public OTS calendars
|
|
148
|
+
'https://a.pool.opentimestamps.org',
|
|
149
|
+
'https://b.pool.opentimestamps.org',
|
|
150
|
+
'https://a.pool.eternitywall.com',
|
|
151
|
+
],
|
|
152
|
+
timeoutMs: 30000,
|
|
153
|
+
retries: 3,
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Ethereum Provider (On-Chain Anchor)
|
|
158
|
+
|
|
159
|
+
Publishes anchor Merkle roots as calldata in Ethereum transactions. Provides cryptographic proof of existence at a specific block height.
|
|
160
|
+
|
|
161
|
+
**Proof level:** `publicly-timestamped`
|
|
162
|
+
**Peer dependency:** `ethers`
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { EthereumProvider } from '@framers/agentos-ext-anchor-providers';
|
|
166
|
+
|
|
167
|
+
const provider = new EthereumProvider({
|
|
168
|
+
rpcUrl: 'https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY', // Required
|
|
169
|
+
signerPrivateKey: '0x...', // Required: hex private key
|
|
170
|
+
chainId: 1, // Default: 1 (mainnet)
|
|
171
|
+
contractAddress: '0x...', // Optional: anchor storage contract
|
|
172
|
+
gasLimit: 100000, // Optional: gas limit override
|
|
173
|
+
timeoutMs: 60000,
|
|
174
|
+
retries: 3,
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Composite Usage
|
|
179
|
+
|
|
180
|
+
Use `CompositeAnchorProvider` from `@framers/agentos` to publish to multiple backends simultaneously:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { CompositeAnchorProvider } from '@framers/agentos';
|
|
184
|
+
import { RekorProvider, WormSnapshotProvider } from '@framers/agentos-ext-anchor-providers';
|
|
185
|
+
|
|
186
|
+
const provider = new CompositeAnchorProvider([
|
|
187
|
+
new WormSnapshotProvider({ bucket: 'my-bucket', region: 'us-east-1' }),
|
|
188
|
+
new RekorProvider(),
|
|
189
|
+
]);
|
|
190
|
+
|
|
191
|
+
// Publishes to both WORM and Rekor in parallel
|
|
192
|
+
// Proof level: publicly-auditable (highest among children)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Or via config with the composite type:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
registerExtensionProviders();
|
|
199
|
+
|
|
200
|
+
const provider = createAnchorProvider({
|
|
201
|
+
type: 'composite',
|
|
202
|
+
targets: [
|
|
203
|
+
{ type: 'worm-snapshot', options: { bucket: 'my-bucket', region: 'us-east-1' } },
|
|
204
|
+
{ type: 'rekor' },
|
|
205
|
+
],
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Architecture
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
213
|
+
│ @framers/agentos (core) │
|
|
214
|
+
│ │
|
|
215
|
+
│ AnchorManager ──→ AnchorProvider interface │
|
|
216
|
+
│ │ ↑ │
|
|
217
|
+
│ │ ┌─────┴──────┐ │
|
|
218
|
+
│ │ │NoneProvider│ (built-in, local-only) │
|
|
219
|
+
│ │ └────────────┘ │
|
|
220
|
+
│ │ ┌──────────────────┐ │
|
|
221
|
+
│ │ │CompositeProvider │ (built-in, multi-target) │
|
|
222
|
+
│ │ └──────────────────┘ │
|
|
223
|
+
│ │ │
|
|
224
|
+
│ createAnchorProvider() ←─── registerAnchorProviderFactory() │
|
|
225
|
+
└──────────────────────┬───────────────────────────────────────────┘
|
|
226
|
+
│ (registry pattern)
|
|
227
|
+
┌──────────────────────▼───────────────────────────────────────────┐
|
|
228
|
+
│ @framers/agentos-ext-anchor-providers │
|
|
229
|
+
│ │
|
|
230
|
+
│ registerExtensionProviders() │
|
|
231
|
+
│ │ │
|
|
232
|
+
│ ├── WormSnapshotProvider (externally-archived) │
|
|
233
|
+
│ ├── RekorProvider (publicly-auditable) │
|
|
234
|
+
│ ├── OpenTimestampsProvider(publicly-timestamped) │
|
|
235
|
+
│ ├── EthereumProvider (publicly-timestamped) │
|
|
236
|
+
│ └── SolanaProvider (publicly-timestamped) │
|
|
237
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Writing Custom Providers
|
|
241
|
+
|
|
242
|
+
Implement the `AnchorProvider` interface from `@framers/agentos`:
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import type { AnchorProvider, AnchorRecord, AnchorProviderResult, ProofLevel } from '@framers/agentos';
|
|
246
|
+
|
|
247
|
+
export class MyCustomProvider implements AnchorProvider {
|
|
248
|
+
readonly id = 'my-custom';
|
|
249
|
+
readonly name = 'My Custom Provider';
|
|
250
|
+
readonly proofLevel: ProofLevel = 'externally-archived';
|
|
251
|
+
|
|
252
|
+
async publish(anchor: AnchorRecord): Promise<AnchorProviderResult> {
|
|
253
|
+
try {
|
|
254
|
+
// Your publishing logic here
|
|
255
|
+
const ref = await publishToMyBackend(anchor);
|
|
256
|
+
return { providerId: this.id, success: true, externalRef: ref };
|
|
257
|
+
} catch (e) {
|
|
258
|
+
return { providerId: this.id, success: false, error: String(e) };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async verify(anchor: AnchorRecord): Promise<boolean> {
|
|
263
|
+
// Verify the anchor against the external record
|
|
264
|
+
return verifyAgainstMyBackend(anchor);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async dispose(): Promise<void> {
|
|
268
|
+
// Cleanup resources
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Register it with the core factory:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { registerAnchorProviderFactory } from '@framers/agentos';
|
|
277
|
+
import { MyCustomProvider } from './MyCustomProvider';
|
|
278
|
+
|
|
279
|
+
registerAnchorProviderFactory('my-custom', (opts) => new MyCustomProvider(opts));
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Utilities
|
|
283
|
+
|
|
284
|
+
### `fetchWithRetry(url, init, options)`
|
|
285
|
+
|
|
286
|
+
HTTP fetch wrapper with exponential backoff retry. Used internally by providers that communicate over HTTP.
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { fetchWithRetry } from '@framers/agentos-ext-anchor-providers';
|
|
290
|
+
|
|
291
|
+
const response = await fetchWithRetry('https://api.example.com/anchor', {
|
|
292
|
+
method: 'POST',
|
|
293
|
+
body: JSON.stringify(data),
|
|
294
|
+
}, { timeoutMs: 10000, retries: 3 });
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### `canonicalizeAnchor(anchor)`
|
|
298
|
+
|
|
299
|
+
Deterministic JSON serialization of an `AnchorRecord` with sorted keys. Ensures all providers hash the same byte representation.
|
|
300
|
+
|
|
301
|
+
### `hashCanonicalAnchor(anchor)`
|
|
302
|
+
|
|
303
|
+
Computes SHA-256 hex digest of the canonical anchor representation.
|
|
304
|
+
|
|
305
|
+
## Implementation Status
|
|
306
|
+
|
|
307
|
+
| Provider | Status | Notes |
|
|
308
|
+
|----------|--------|-------|
|
|
309
|
+
| WormSnapshotProvider | Stub | Requires `@aws-sdk/client-s3` implementation |
|
|
310
|
+
| RekorProvider | Stub | Requires `sigstore` SDK implementation |
|
|
311
|
+
| OpenTimestampsProvider | Stub | Requires `opentimestamps` implementation |
|
|
312
|
+
| EthereumProvider | Stub | Requires `ethers` implementation |
|
|
313
|
+
| SolanaProvider | Implemented | Requires `@solana/web3.js` (and a funded signer) |
|
|
314
|
+
|
|
315
|
+
All providers **except SolanaProvider** currently return `{ success: false }` from `publish()` until their respective SDK integrations are implemented. SolanaProvider is functional when its optional peer dependencies are installed and the configured signer is funded.
|
|
316
|
+
|
|
317
|
+
## Testing
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# Run all tests
|
|
321
|
+
pnpm test
|
|
322
|
+
|
|
323
|
+
# Run with coverage
|
|
324
|
+
pnpm test:coverage
|
|
325
|
+
|
|
326
|
+
# Watch mode
|
|
327
|
+
pnpm test:watch
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Test Structure
|
|
331
|
+
|
|
332
|
+
| File | Description |
|
|
333
|
+
|------|-------------|
|
|
334
|
+
| `test/providers.spec.ts` | Unit tests for all 4 providers — identity, stub behavior, config |
|
|
335
|
+
| `test/register.spec.ts` | Registration tests — verifies factories are registered with core |
|
|
336
|
+
| `test/integration.spec.ts` | End-to-end integration — factory creation, provider identity, stub behavior |
|
|
337
|
+
| `test/utils.spec.ts` | Utility tests — canonicalization, SHA-256 hashing, HTTP retry |
|
|
338
|
+
| `test/types.spec.ts` | Config resolution tests — default values, overrides |
|
|
339
|
+
|
|
340
|
+
## Related Packages
|
|
341
|
+
|
|
342
|
+
| Package | Description | Link |
|
|
343
|
+
|---------|-------------|------|
|
|
344
|
+
| `@framers/agentos` | Core AgentOS framework with `AnchorProvider` interface, `AnchorManager`, registry | [packages/agentos](https://github.com/framersai/agentos) |
|
|
345
|
+
| `@framers/agentos` provenance types | `AnchorProvider`, `ProofLevel`, `AnchorProviderResult` interfaces | [`src/core/provenance/types.ts`](https://github.com/framersai/agentos/blob/master/src/core/provenance/types.ts) |
|
|
346
|
+
| `@framers/agentos` factory | `createAnchorProvider()`, `registerAnchorProviderFactory()` | [`src/core/provenance/anchoring/providers/createAnchorProvider.ts`](https://github.com/framersai/agentos/blob/master/src/core/provenance/anchoring/providers/createAnchorProvider.ts) |
|
|
347
|
+
| `@framers/agentos` built-in providers | `NoneProvider`, `CompositeAnchorProvider` | [`src/core/provenance/anchoring/providers/`](https://github.com/framersai/agentos/blob/master/src/core/provenance/anchoring/providers/) |
|
|
348
|
+
| `@framers/agentos` AnchorManager | Periodic anchoring with external provider support | [`src/core/provenance/anchoring/AnchorManager.ts`](https://github.com/framersai/agentos/blob/master/src/core/provenance/anchoring/AnchorManager.ts) |
|
|
349
|
+
| `@framers/agentos` profiles | `sealedAuditable()` convenience profile | [`src/core/provenance/config/PolicyProfiles.ts`](https://github.com/framersai/agentos/blob/master/src/core/provenance/config/PolicyProfiles.ts) |
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file index.ts
|
|
3
|
+
* @description Main entry point for @framers/agentos-ext-anchor-providers.
|
|
4
|
+
*
|
|
5
|
+
* External anchor providers for the AgentOS provenance system:
|
|
6
|
+
* - **WormSnapshotProvider** — S3 Object Lock / WORM storage (externally-archived)
|
|
7
|
+
* - **RekorProvider** — Sigstore Rekor transparency log (publicly-auditable)
|
|
8
|
+
* - **OpenTimestampsProvider** — Bitcoin-anchored timestamping (publicly-timestamped)
|
|
9
|
+
* - **EthereumProvider** — Ethereum on-chain anchor (publicly-timestamped)
|
|
10
|
+
* - **SolanaProvider** — Solana on-chain anchor (publicly-timestamped)
|
|
11
|
+
*
|
|
12
|
+
* ## Quick Start
|
|
13
|
+
*
|
|
14
|
+
* ### Option 1: Config-driven (via registry)
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { registerExtensionProviders } from '@framers/agentos-ext-anchor-providers';
|
|
17
|
+
* import { createAnchorProvider } from '@framers/agentos';
|
|
18
|
+
*
|
|
19
|
+
* registerExtensionProviders();
|
|
20
|
+
* const provider = createAnchorProvider({ type: 'rekor' });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* ### Option 2: Direct construction
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
|
|
26
|
+
*
|
|
27
|
+
* const provider = new RekorProvider({ serverUrl: 'https://rekor.sigstore.dev' });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @module @framers/agentos-ext-anchor-providers
|
|
31
|
+
*/
|
|
32
|
+
export { registerExtensionProviders } from './register.js';
|
|
33
|
+
export { WormSnapshotProvider } from './providers/WormSnapshotProvider.js';
|
|
34
|
+
export type { WormSnapshotProviderConfig } from './providers/WormSnapshotProvider.js';
|
|
35
|
+
export { RekorProvider } from './providers/RekorProvider.js';
|
|
36
|
+
export type { RekorProviderConfig } from './providers/RekorProvider.js';
|
|
37
|
+
export { OpenTimestampsProvider } from './providers/OpenTimestampsProvider.js';
|
|
38
|
+
export type { OpenTimestampsProviderConfig } from './providers/OpenTimestampsProvider.js';
|
|
39
|
+
export { EthereumProvider } from './providers/EthereumProvider.js';
|
|
40
|
+
export type { EthereumProviderConfig } from './providers/EthereumProvider.js';
|
|
41
|
+
export { SolanaProvider } from './providers/SolanaProvider.js';
|
|
42
|
+
export type { SolanaProviderConfig } from './providers/SolanaProvider.js';
|
|
43
|
+
export type { BaseProviderConfig } from './types.js';
|
|
44
|
+
export { resolveBaseConfig } from './types.js';
|
|
45
|
+
export { fetchWithRetry } from './utils/http-client.js';
|
|
46
|
+
export type { HttpRequestOptions } from './utils/http-client.js';
|
|
47
|
+
export { canonicalizeAnchor, hashCanonicalAnchor } from './utils/serialization.js';
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAG3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,YAAY,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AAE1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,YAAY,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAG1E,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file index.ts
|
|
3
|
+
* @description Main entry point for @framers/agentos-ext-anchor-providers.
|
|
4
|
+
*
|
|
5
|
+
* External anchor providers for the AgentOS provenance system:
|
|
6
|
+
* - **WormSnapshotProvider** — S3 Object Lock / WORM storage (externally-archived)
|
|
7
|
+
* - **RekorProvider** — Sigstore Rekor transparency log (publicly-auditable)
|
|
8
|
+
* - **OpenTimestampsProvider** — Bitcoin-anchored timestamping (publicly-timestamped)
|
|
9
|
+
* - **EthereumProvider** — Ethereum on-chain anchor (publicly-timestamped)
|
|
10
|
+
* - **SolanaProvider** — Solana on-chain anchor (publicly-timestamped)
|
|
11
|
+
*
|
|
12
|
+
* ## Quick Start
|
|
13
|
+
*
|
|
14
|
+
* ### Option 1: Config-driven (via registry)
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { registerExtensionProviders } from '@framers/agentos-ext-anchor-providers';
|
|
17
|
+
* import { createAnchorProvider } from '@framers/agentos';
|
|
18
|
+
*
|
|
19
|
+
* registerExtensionProviders();
|
|
20
|
+
* const provider = createAnchorProvider({ type: 'rekor' });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* ### Option 2: Direct construction
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { RekorProvider } from '@framers/agentos-ext-anchor-providers';
|
|
26
|
+
*
|
|
27
|
+
* const provider = new RekorProvider({ serverUrl: 'https://rekor.sigstore.dev' });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @module @framers/agentos-ext-anchor-providers
|
|
31
|
+
*/
|
|
32
|
+
// Registry
|
|
33
|
+
export { registerExtensionProviders } from './register.js';
|
|
34
|
+
// Providers
|
|
35
|
+
export { WormSnapshotProvider } from './providers/WormSnapshotProvider.js';
|
|
36
|
+
export { RekorProvider } from './providers/RekorProvider.js';
|
|
37
|
+
export { OpenTimestampsProvider } from './providers/OpenTimestampsProvider.js';
|
|
38
|
+
export { EthereumProvider } from './providers/EthereumProvider.js';
|
|
39
|
+
export { SolanaProvider } from './providers/SolanaProvider.js';
|
|
40
|
+
export { resolveBaseConfig } from './types.js';
|
|
41
|
+
// Utilities
|
|
42
|
+
export { fetchWithRetry } from './utils/http-client.js';
|
|
43
|
+
export { canonicalizeAnchor, hashCanonicalAnchor } from './utils/serialization.js';
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,WAAW;AACX,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAE3D,YAAY;AACZ,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAG3E,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAG/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAGnE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAK/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,YAAY;AACZ,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file EthereumProvider.ts
|
|
3
|
+
* @description Ethereum on-chain anchor provider.
|
|
4
|
+
* Publishes anchor Merkle roots as calldata in Ethereum transactions.
|
|
5
|
+
*
|
|
6
|
+
* Proof level: `publicly-timestamped`
|
|
7
|
+
* Required peer dependency: `ethers`
|
|
8
|
+
*
|
|
9
|
+
* @module @framers/agentos-ext-anchor-providers
|
|
10
|
+
*/
|
|
11
|
+
import type { AnchorProvider, AnchorRecord, AnchorProviderResult, ProofLevel } from '@framers/agentos';
|
|
12
|
+
import type { BaseProviderConfig } from '../types.js';
|
|
13
|
+
export interface EthereumProviderConfig extends BaseProviderConfig {
|
|
14
|
+
/** JSON-RPC endpoint URL. */
|
|
15
|
+
rpcUrl: string;
|
|
16
|
+
/** Contract address for anchor storage (optional — can use raw calldata tx). */
|
|
17
|
+
contractAddress?: string;
|
|
18
|
+
/** Private key hex for signing transactions. */
|
|
19
|
+
signerPrivateKey?: string;
|
|
20
|
+
/** Chain ID. Default: 1 (mainnet). */
|
|
21
|
+
chainId?: number;
|
|
22
|
+
/** Gas limit override. Default: auto-estimate. */
|
|
23
|
+
gasLimit?: number;
|
|
24
|
+
}
|
|
25
|
+
export declare class EthereumProvider implements AnchorProvider {
|
|
26
|
+
readonly id = "ethereum";
|
|
27
|
+
readonly name = "Ethereum On-Chain Anchor";
|
|
28
|
+
readonly proofLevel: ProofLevel;
|
|
29
|
+
private readonly config;
|
|
30
|
+
private readonly baseConfig;
|
|
31
|
+
constructor(config: EthereumProviderConfig);
|
|
32
|
+
publish(anchor: AnchorRecord): Promise<AnchorProviderResult>;
|
|
33
|
+
verify(anchor: AnchorRecord): Promise<boolean>;
|
|
34
|
+
dispose(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=EthereumProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EthereumProvider.d.ts","sourceRoot":"","sources":["../../src/providers/EthereumProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACvG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAItD,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,gBAAiB,YAAW,cAAc;IACrD,QAAQ,CAAC,EAAE,cAAc;IACzB,QAAQ,CAAC,IAAI,8BAA8B;IAC3C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAA0B;IAEzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;gBAE9C,MAAM,EAAE,sBAAsB;IAQpC,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA8B5D,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ9C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file EthereumProvider.ts
|
|
3
|
+
* @description Ethereum on-chain anchor provider.
|
|
4
|
+
* Publishes anchor Merkle roots as calldata in Ethereum transactions.
|
|
5
|
+
*
|
|
6
|
+
* Proof level: `publicly-timestamped`
|
|
7
|
+
* Required peer dependency: `ethers`
|
|
8
|
+
*
|
|
9
|
+
* @module @framers/agentos-ext-anchor-providers
|
|
10
|
+
*/
|
|
11
|
+
import { resolveBaseConfig } from '../types.js';
|
|
12
|
+
import { hashCanonicalAnchor } from '../utils/serialization.js';
|
|
13
|
+
export class EthereumProvider {
|
|
14
|
+
id = 'ethereum';
|
|
15
|
+
name = 'Ethereum On-Chain Anchor';
|
|
16
|
+
proofLevel = 'publicly-timestamped';
|
|
17
|
+
config;
|
|
18
|
+
baseConfig;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = {
|
|
21
|
+
chainId: 1,
|
|
22
|
+
...config,
|
|
23
|
+
};
|
|
24
|
+
this.baseConfig = resolveBaseConfig(config);
|
|
25
|
+
}
|
|
26
|
+
async publish(anchor) {
|
|
27
|
+
// TODO: Implement using ethers.js or viem
|
|
28
|
+
//
|
|
29
|
+
// Implementation outline:
|
|
30
|
+
// 1. Compute SHA-256 of canonical anchor: hashCanonicalAnchor(anchor)
|
|
31
|
+
// 2. Create ethers.JsonRpcProvider(this.config.rpcUrl)
|
|
32
|
+
// 3. Create ethers.Wallet(this.config.signerPrivateKey, provider)
|
|
33
|
+
// 4. If contractAddress is set:
|
|
34
|
+
// - ABI-encode call to `anchor(bytes32 merkleRoot)` on the contract
|
|
35
|
+
// - Send contract transaction
|
|
36
|
+
// 5. If no contractAddress (raw calldata):
|
|
37
|
+
// - Send self-transfer with 0x + anchorHash as calldata
|
|
38
|
+
// 6. Wait for transaction receipt (1 confirmation)
|
|
39
|
+
// 7. Return { success: true, externalRef: `eth:${chainId}:${txHash}`,
|
|
40
|
+
// metadata: { blockNumber, blockHash, gasUsed, chainId } }
|
|
41
|
+
try {
|
|
42
|
+
const _hash = await hashCanonicalAnchor(anchor);
|
|
43
|
+
throw new Error('EthereumProvider is not yet implemented. ' +
|
|
44
|
+
'Install ethers.js and implement the Ethereum on-chain anchor integration.');
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
return {
|
|
48
|
+
providerId: this.id,
|
|
49
|
+
success: false,
|
|
50
|
+
error: e instanceof Error ? e.message : String(e),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async verify(anchor) {
|
|
55
|
+
// TODO: Parse txHash from externalRef, fetch transaction receipt,
|
|
56
|
+
// decode calldata, compare with anchor hash
|
|
57
|
+
if (!anchor.externalRef)
|
|
58
|
+
return false;
|
|
59
|
+
console.warn('[EthereumProvider] verify() is not yet implemented');
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
async dispose() {
|
|
63
|
+
// TODO: Disconnect provider if persistent connection was established
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=EthereumProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EthereumProvider.js","sourceRoot":"","sources":["../../src/providers/EthereumProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAehE,MAAM,OAAO,gBAAgB;IAClB,EAAE,GAAG,UAAU,CAAC;IAChB,IAAI,GAAG,0BAA0B,CAAC;IAClC,UAAU,GAAe,sBAAsB,CAAC;IAExC,MAAM,CAAyB;IAC/B,UAAU,CAA+B;IAE1D,YAAY,MAA8B;QACxC,IAAI,CAAC,MAAM,GAAG;YACZ,OAAO,EAAE,CAAC;YACV,GAAG,MAAM;SACV,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAoB;QAChC,0CAA0C;QAC1C,EAAE;QACF,0BAA0B;QAC1B,wEAAwE;QACxE,yDAAyD;QACzD,oEAAoE;QACpE,kCAAkC;QAClC,yEAAyE;QACzE,mCAAmC;QACnC,6CAA6C;QAC7C,6DAA6D;QAC7D,qDAAqD;QACrD,wEAAwE;QACxE,wEAAwE;QACxE,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,IAAI,KAAK,CACb,2CAA2C;gBAC3C,2EAA2E,CAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,CAAU,EAAE,CAAC;YACpB,OAAO;gBACL,UAAU,EAAE,IAAI,CAAC,EAAE;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;aAClD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAoB;QAC/B,kEAAkE;QAClE,8CAA8C;QAC9C,IAAI,CAAC,MAAM,CAAC,WAAW;YAAE,OAAO,KAAK,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO;QACX,qEAAqE;IACvE,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file OpenTimestampsProvider.ts
|
|
3
|
+
* @description Bitcoin-anchored timestamping via the OpenTimestamps protocol.
|
|
4
|
+
* Creates OTS timestamps for anchor Merkle roots and submits to calendar servers.
|
|
5
|
+
*
|
|
6
|
+
* Proof level: `publicly-timestamped`
|
|
7
|
+
* Required peer dependency: `opentimestamps`
|
|
8
|
+
*
|
|
9
|
+
* @module @framers/agentos-ext-anchor-providers
|
|
10
|
+
*/
|
|
11
|
+
import type { AnchorProvider, AnchorRecord, AnchorProviderResult, ProofLevel } from '@framers/agentos';
|
|
12
|
+
import type { BaseProviderConfig } from '../types.js';
|
|
13
|
+
export interface OpenTimestampsProviderConfig extends BaseProviderConfig {
|
|
14
|
+
/** OTS calendar server URLs. Default: public OpenTimestamps calendars. */
|
|
15
|
+
calendarUrls?: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare class OpenTimestampsProvider implements AnchorProvider {
|
|
18
|
+
readonly id = "opentimestamps";
|
|
19
|
+
readonly name = "OpenTimestamps (Bitcoin)";
|
|
20
|
+
readonly proofLevel: ProofLevel;
|
|
21
|
+
private readonly config;
|
|
22
|
+
private readonly baseConfig;
|
|
23
|
+
constructor(config?: OpenTimestampsProviderConfig);
|
|
24
|
+
publish(anchor: AnchorRecord): Promise<AnchorProviderResult>;
|
|
25
|
+
verify(anchor: AnchorRecord): Promise<boolean>;
|
|
26
|
+
dispose(): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=OpenTimestampsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenTimestampsProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OpenTimestampsProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACvG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAItD,MAAM,WAAW,4BAA6B,SAAQ,kBAAkB;IACtE,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAQD,qBAAa,sBAAuB,YAAW,cAAc;IAC3D,QAAQ,CAAC,EAAE,oBAAoB;IAC/B,QAAQ,CAAC,IAAI,8BAA8B;IAC3C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAA0B;IAEzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;gBAE9C,MAAM,GAAE,4BAAiC;IAU/C,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA6B5D,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ9C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
|