@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.
Files changed (65) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +353 -0
  3. package/dist/index.d.ts +48 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +44 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/providers/EthereumProvider.d.ts +36 -0
  8. package/dist/providers/EthereumProvider.d.ts.map +1 -0
  9. package/dist/providers/EthereumProvider.js +66 -0
  10. package/dist/providers/EthereumProvider.js.map +1 -0
  11. package/dist/providers/OpenTimestampsProvider.d.ts +28 -0
  12. package/dist/providers/OpenTimestampsProvider.d.ts.map +1 -0
  13. package/dist/providers/OpenTimestampsProvider.js +72 -0
  14. package/dist/providers/OpenTimestampsProvider.js.map +1 -0
  15. package/dist/providers/RekorProvider.d.ts +28 -0
  16. package/dist/providers/RekorProvider.d.ts.map +1 -0
  17. package/dist/providers/RekorProvider.js +68 -0
  18. package/dist/providers/RekorProvider.js.map +1 -0
  19. package/dist/providers/SolanaProvider.d.ts +62 -0
  20. package/dist/providers/SolanaProvider.d.ts.map +1 -0
  21. package/dist/providers/SolanaProvider.js +256 -0
  22. package/dist/providers/SolanaProvider.js.map +1 -0
  23. package/dist/providers/WormSnapshotProvider.d.ts +35 -0
  24. package/dist/providers/WormSnapshotProvider.d.ts.map +1 -0
  25. package/dist/providers/WormSnapshotProvider.js +64 -0
  26. package/dist/providers/WormSnapshotProvider.js.map +1 -0
  27. package/dist/register.d.ts +31 -0
  28. package/dist/register.d.ts.map +1 -0
  29. package/dist/register.js +47 -0
  30. package/dist/register.js.map +1 -0
  31. package/dist/types.d.ts +20 -0
  32. package/dist/types.d.ts.map +1 -0
  33. package/dist/types.js +15 -0
  34. package/dist/types.js.map +1 -0
  35. package/dist/utils/http-client.d.ts +23 -0
  36. package/dist/utils/http-client.d.ts.map +1 -0
  37. package/dist/utils/http-client.js +53 -0
  38. package/dist/utils/http-client.js.map +1 -0
  39. package/dist/utils/index.d.ts +4 -0
  40. package/dist/utils/index.d.ts.map +1 -0
  41. package/dist/utils/index.js +3 -0
  42. package/dist/utils/index.js.map +1 -0
  43. package/dist/utils/serialization.d.ts +16 -0
  44. package/dist/utils/serialization.d.ts.map +1 -0
  45. package/dist/utils/serialization.js +30 -0
  46. package/dist/utils/serialization.js.map +1 -0
  47. package/manifest.json +100 -0
  48. package/package.json +103 -0
  49. package/src/index.ts +59 -0
  50. package/src/providers/EthereumProvider.ts +87 -0
  51. package/src/providers/OpenTimestampsProvider.ts +86 -0
  52. package/src/providers/RekorProvider.ts +82 -0
  53. package/src/providers/SolanaProvider.ts +439 -0
  54. package/src/providers/WormSnapshotProvider.ts +84 -0
  55. package/src/register.ts +69 -0
  56. package/src/types.ts +27 -0
  57. package/src/utils/http-client.ts +75 -0
  58. package/src/utils/index.ts +3 -0
  59. package/src/utils/serialization.ts +33 -0
  60. package/test/integration.spec.ts +175 -0
  61. package/test/providers.spec.ts +163 -0
  62. package/test/register.spec.ts +69 -0
  63. package/test/types.spec.ts +55 -0
  64. package/test/utils.spec.ts +225 -0
  65. package/tsconfig.json +21 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @file register.ts
3
+ * @description Registers all anchor provider factories with the core AgentOS factory.
4
+ * Call `registerExtensionProviders()` once at startup to enable config-driven
5
+ * provider creation via `createAnchorProvider()`.
6
+ *
7
+ * @module @framers/agentos-ext-anchor-providers
8
+ */
9
+ /**
10
+ * Register all anchor provider factories with the core AgentOS provider registry.
11
+ * Call once at application startup, before creating any AnchorProvider via config.
12
+ *
13
+ * Safe to call multiple times — subsequent calls are no-ops.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { registerExtensionProviders } from '@framers/agentos-ext-anchor-providers';
18
+ * import { createAnchorProvider } from '@framers/agentos';
19
+ *
20
+ * // Register at startup
21
+ * registerExtensionProviders();
22
+ *
23
+ * // Now config-driven creation works:
24
+ * const provider = createAnchorProvider({
25
+ * type: 'rekor',
26
+ * options: { serverUrl: 'https://rekor.sigstore.dev' },
27
+ * });
28
+ * ```
29
+ */
30
+ export declare function registerExtensionProviders(): void;
31
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAwBjD"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @file register.ts
3
+ * @description Registers all anchor provider factories with the core AgentOS factory.
4
+ * Call `registerExtensionProviders()` once at startup to enable config-driven
5
+ * provider creation via `createAnchorProvider()`.
6
+ *
7
+ * @module @framers/agentos-ext-anchor-providers
8
+ */
9
+ import { registerAnchorProviderFactory } from '@framers/agentos';
10
+ import { WormSnapshotProvider } from './providers/WormSnapshotProvider.js';
11
+ import { RekorProvider } from './providers/RekorProvider.js';
12
+ import { OpenTimestampsProvider } from './providers/OpenTimestampsProvider.js';
13
+ import { EthereumProvider } from './providers/EthereumProvider.js';
14
+ import { SolanaProvider } from './providers/SolanaProvider.js';
15
+ let registered = false;
16
+ /**
17
+ * Register all anchor provider factories with the core AgentOS provider registry.
18
+ * Call once at application startup, before creating any AnchorProvider via config.
19
+ *
20
+ * Safe to call multiple times — subsequent calls are no-ops.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * import { registerExtensionProviders } from '@framers/agentos-ext-anchor-providers';
25
+ * import { createAnchorProvider } from '@framers/agentos';
26
+ *
27
+ * // Register at startup
28
+ * registerExtensionProviders();
29
+ *
30
+ * // Now config-driven creation works:
31
+ * const provider = createAnchorProvider({
32
+ * type: 'rekor',
33
+ * options: { serverUrl: 'https://rekor.sigstore.dev' },
34
+ * });
35
+ * ```
36
+ */
37
+ export function registerExtensionProviders() {
38
+ if (registered)
39
+ return;
40
+ registerAnchorProviderFactory('worm-snapshot', (opts) => new WormSnapshotProvider(opts));
41
+ registerAnchorProviderFactory('rekor', (opts) => new RekorProvider(opts));
42
+ registerAnchorProviderFactory('opentimestamps', (opts) => new OpenTimestampsProvider(opts));
43
+ registerAnchorProviderFactory('ethereum', (opts) => new EthereumProvider(opts));
44
+ registerAnchorProviderFactory('solana', (opts) => new SolanaProvider(opts));
45
+ registered = true;
46
+ }
47
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAE3E,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAE/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAG/D,IAAI,UAAU,GAAG,KAAK,CAAC;AAEvB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,0BAA0B;IACxC,IAAI,UAAU;QAAE,OAAO;IAEvB,6BAA6B,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,EAAE,CACtD,IAAI,oBAAoB,CAAC,IAA6C,CAAC,CACxE,CAAC;IAEF,6BAA6B,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAC9C,IAAI,aAAa,CAAC,IAAsC,CAAC,CAC1D,CAAC;IAEF,6BAA6B,CAAC,gBAAgB,EAAE,CAAC,IAAI,EAAE,EAAE,CACvD,IAAI,sBAAsB,CAAC,IAA+C,CAAC,CAC5E,CAAC;IAEF,6BAA6B,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CACjD,IAAI,gBAAgB,CAAC,IAAyC,CAAC,CAChE,CAAC;IAEF,6BAA6B,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAC/C,IAAI,cAAc,CAAC,IAAuC,CAAC,CAC5D,CAAC;IAEF,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @file types.ts
3
+ * @description Shared types for anchor provider implementations.
4
+ */
5
+ /**
6
+ * Base configuration shared by all anchor providers.
7
+ */
8
+ export interface BaseProviderConfig {
9
+ /** Request timeout in milliseconds. Default: 30000. */
10
+ timeoutMs?: number;
11
+ /** Number of retries on transient failures. Default: 3. */
12
+ retries?: number;
13
+ /** Base delay between retries in milliseconds. Default: 1000. */
14
+ retryDelayMs?: number;
15
+ }
16
+ /**
17
+ * Resolve a base config with defaults.
18
+ */
19
+ export declare function resolveBaseConfig(config?: Partial<BaseProviderConfig>): Required<BaseProviderConfig>;
20
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAMpG"}
package/dist/types.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @file types.ts
3
+ * @description Shared types for anchor provider implementations.
4
+ */
5
+ /**
6
+ * Resolve a base config with defaults.
7
+ */
8
+ export function resolveBaseConfig(config) {
9
+ return {
10
+ timeoutMs: config?.timeoutMs ?? 30_000,
11
+ retries: config?.retries ?? 3,
12
+ retryDelayMs: config?.retryDelayMs ?? 1_000,
13
+ };
14
+ }
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAoC;IACpE,OAAO;QACL,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,MAAM;QACtC,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,CAAC;QAC7B,YAAY,EAAE,MAAM,EAAE,YAAY,IAAI,KAAK;KAC5C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file http-client.ts
3
+ * @description Shared HTTP fetch wrapper with retry and timeout for anchor providers.
4
+ */
5
+ export interface HttpRequestOptions {
6
+ /** Request timeout in milliseconds. */
7
+ timeoutMs?: number;
8
+ /** Number of retries on transient failures (5xx, network errors). */
9
+ retries?: number;
10
+ /** Base delay between retries in milliseconds (exponential backoff). */
11
+ retryDelayMs?: number;
12
+ }
13
+ /**
14
+ * Fetch with exponential backoff retry on transient failures.
15
+ *
16
+ * @param url - The URL to fetch.
17
+ * @param init - Standard RequestInit options.
18
+ * @param options - Retry and timeout configuration.
19
+ * @returns The fetch Response.
20
+ * @throws On non-transient errors or after all retries exhausted.
21
+ */
22
+ export declare function fetchWithRetry(url: string, init?: RequestInit, options?: HttpRequestOptions): Promise<Response>;
23
+ //# sourceMappingURL=http-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/utils/http-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,WAAgB,EACtB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CA2CnB"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @file http-client.ts
3
+ * @description Shared HTTP fetch wrapper with retry and timeout for anchor providers.
4
+ */
5
+ const DEFAULT_TIMEOUT_MS = 30_000;
6
+ const DEFAULT_RETRIES = 3;
7
+ const DEFAULT_RETRY_DELAY_MS = 1_000;
8
+ /**
9
+ * Fetch with exponential backoff retry on transient failures.
10
+ *
11
+ * @param url - The URL to fetch.
12
+ * @param init - Standard RequestInit options.
13
+ * @param options - Retry and timeout configuration.
14
+ * @returns The fetch Response.
15
+ * @throws On non-transient errors or after all retries exhausted.
16
+ */
17
+ export async function fetchWithRetry(url, init = {}, options) {
18
+ const maxRetries = options?.retries ?? DEFAULT_RETRIES;
19
+ const baseDelay = options?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
20
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
21
+ let lastError;
22
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
23
+ try {
24
+ const controller = new AbortController();
25
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
26
+ const response = await fetch(url, {
27
+ ...init,
28
+ signal: controller.signal,
29
+ });
30
+ clearTimeout(timeout);
31
+ // Don't retry client errors (4xx), only server errors (5xx)
32
+ if (response.ok || (response.status >= 400 && response.status < 500)) {
33
+ return response;
34
+ }
35
+ // Server error — retry
36
+ lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);
37
+ }
38
+ catch (err) {
39
+ lastError = err instanceof Error ? err : new Error(String(err));
40
+ // Don't retry aborted requests (timeout)
41
+ if (lastError.name === 'AbortError') {
42
+ lastError = new Error(`Request timed out after ${timeoutMs}ms`);
43
+ }
44
+ }
45
+ // Exponential backoff before next retry
46
+ if (attempt < maxRetries) {
47
+ const delay = baseDelay * Math.pow(2, attempt);
48
+ await new Promise(resolve => setTimeout(resolve, delay));
49
+ }
50
+ }
51
+ throw lastError ?? new Error('Request failed after all retries');
52
+ }
53
+ //# sourceMappingURL=http-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/utils/http-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAErC;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,OAAoB,EAAE,EACtB,OAA4B;IAE5B,MAAM,UAAU,GAAG,OAAO,EAAE,OAAO,IAAI,eAAe,CAAC;IACvD,MAAM,SAAS,GAAG,OAAO,EAAE,YAAY,IAAI,sBAAsB,CAAC;IAClE,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,kBAAkB,CAAC;IAE3D,IAAI,SAA4B,CAAC;IAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;YAEhE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,GAAG,IAAI;gBACP,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,YAAY,CAAC,OAAO,CAAC,CAAC;YAEtB,4DAA4D;YAC5D,IAAI,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;gBACrE,OAAO,QAAQ,CAAC;YAClB,CAAC;YAED,uBAAuB;YACvB,SAAS,GAAG,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAEhE,yCAAyC;YACzC,IAAI,SAAS,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBACpC,SAAS,GAAG,IAAI,KAAK,CAAC,2BAA2B,SAAS,IAAI,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,wCAAwC;QACxC,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAC/C,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { fetchWithRetry } from './http-client.js';
2
+ export type { HttpRequestOptions } from './http-client.js';
3
+ export { canonicalizeAnchor, hashCanonicalAnchor } from './serialization.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { fetchWithRetry } from './http-client.js';
2
+ export { canonicalizeAnchor, hashCanonicalAnchor } from './serialization.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file serialization.ts
3
+ * @description Deterministic serialization for anchor records before external publishing.
4
+ */
5
+ import type { AnchorRecord } from '@framers/agentos';
6
+ /**
7
+ * Serialize an AnchorRecord to a canonical JSON string with sorted keys.
8
+ * Ensures all providers hash/publish the same byte representation.
9
+ */
10
+ export declare function canonicalizeAnchor(anchor: AnchorRecord): string;
11
+ /**
12
+ * Compute a SHA-256 hex digest of the canonical anchor representation.
13
+ * Used by providers as the hash to publish externally.
14
+ */
15
+ export declare function hashCanonicalAnchor(anchor: AnchorRecord): Promise<string>;
16
+ //# sourceMappingURL=serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/utils/serialization.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAW/D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/E"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file serialization.ts
3
+ * @description Deterministic serialization for anchor records before external publishing.
4
+ */
5
+ import { createHash } from 'crypto';
6
+ /**
7
+ * Serialize an AnchorRecord to a canonical JSON string with sorted keys.
8
+ * Ensures all providers hash/publish the same byte representation.
9
+ */
10
+ export function canonicalizeAnchor(anchor) {
11
+ const canonical = {
12
+ eventCount: anchor.eventCount,
13
+ id: anchor.id,
14
+ merkleRoot: anchor.merkleRoot,
15
+ sequenceFrom: anchor.sequenceFrom,
16
+ sequenceTo: anchor.sequenceTo,
17
+ signature: anchor.signature,
18
+ timestamp: anchor.timestamp,
19
+ };
20
+ return JSON.stringify(canonical);
21
+ }
22
+ /**
23
+ * Compute a SHA-256 hex digest of the canonical anchor representation.
24
+ * Used by providers as the hash to publish externally.
25
+ */
26
+ export async function hashCanonicalAnchor(anchor) {
27
+ const canonical = canonicalizeAnchor(anchor);
28
+ return createHash('sha256').update(canonical, 'utf8').digest('hex');
29
+ }
30
+ //# sourceMappingURL=serialization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/utils/serialization.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,MAAM,SAAS,GAAG;QAChB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;IACF,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAoB;IAC5D,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC7C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACtE,CAAC"}
package/manifest.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "$schema": "https://agentos.sh/schemas/extension-manifest-v1.json",
3
+ "id": "com.framers.provenance.anchor-providers",
4
+ "name": "Provenance Anchor Providers",
5
+ "version": "1.0.0",
6
+ "description": "External anchor providers for the AgentOS provenance system — WORM storage, transparency logs, and blockchain timestamping",
7
+ "author": {
8
+ "name": "Frame.dev",
9
+ "email": "support@frame.dev",
10
+ "url": "https://github.com/framersai"
11
+ },
12
+ "license": "MIT",
13
+ "keywords": [
14
+ "provenance",
15
+ "anchor",
16
+ "blockchain",
17
+ "ethereum",
18
+ "opentimestamps",
19
+ "rekor",
20
+ "sigstore",
21
+ "worm",
22
+ "s3-object-lock",
23
+ "transparency-log",
24
+ "tamper-evidence"
25
+ ],
26
+ "agentosVersion": "^0.1.0",
27
+ "categories": ["provenance", "enterprise"],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/framersai/agentos-extensions"
31
+ },
32
+ "extensions": [
33
+ {
34
+ "kind": "provenance",
35
+ "id": "wormSnapshotProvider",
36
+ "displayName": "WORM Snapshot Provider",
37
+ "description": "S3 Object Lock / WORM storage for compliance-grade anchor archival",
38
+ "entry": "./dist/providers/WormSnapshotProvider.js",
39
+ "proofLevel": "externally-archived"
40
+ },
41
+ {
42
+ "kind": "provenance",
43
+ "id": "rekorProvider",
44
+ "displayName": "Rekor Transparency Log Provider",
45
+ "description": "Sigstore Rekor transparency log for publicly auditable anchor records",
46
+ "entry": "./dist/providers/RekorProvider.js",
47
+ "proofLevel": "publicly-auditable"
48
+ },
49
+ {
50
+ "kind": "provenance",
51
+ "id": "openTimestampsProvider",
52
+ "displayName": "OpenTimestamps Provider",
53
+ "description": "Bitcoin-anchored timestamping via the OpenTimestamps protocol",
54
+ "entry": "./dist/providers/OpenTimestampsProvider.js",
55
+ "proofLevel": "publicly-timestamped"
56
+ },
57
+ {
58
+ "kind": "provenance",
59
+ "id": "ethereumProvider",
60
+ "displayName": "Ethereum On-Chain Anchor Provider",
61
+ "description": "Ethereum on-chain anchor with transaction receipt and finalized block proof",
62
+ "entry": "./dist/providers/EthereumProvider.js",
63
+ "proofLevel": "publicly-timestamped"
64
+ },
65
+ {
66
+ "kind": "provenance",
67
+ "id": "solanaProvider",
68
+ "displayName": "Solana On-Chain Anchor Provider",
69
+ "description": "Solana on-chain anchor via the Wunderland program (content hash + manifest hash)",
70
+ "entry": "./dist/providers/SolanaProvider.js",
71
+ "proofLevel": "publicly-timestamped"
72
+ }
73
+ ],
74
+ "configuration": {
75
+ "properties": {
76
+ "provider.type": {
77
+ "type": "string",
78
+ "enum": ["none", "worm-snapshot", "rekor", "opentimestamps", "ethereum", "solana", "composite"],
79
+ "default": "none",
80
+ "description": "Which anchor provider to use for external publishing"
81
+ },
82
+ "provider.endpoint": {
83
+ "type": "string",
84
+ "description": "Provider endpoint URL (e.g., Rekor server, Ethereum RPC)"
85
+ },
86
+ "provider.timeoutMs": {
87
+ "type": "number",
88
+ "default": 30000,
89
+ "description": "Request timeout in milliseconds"
90
+ },
91
+ "provider.retries": {
92
+ "type": "number",
93
+ "default": 3,
94
+ "minimum": 0,
95
+ "maximum": 10,
96
+ "description": "Number of retries on transient failures"
97
+ }
98
+ }
99
+ }
100
+ }
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@framers/agentos-ext-anchor-providers",
3
+ "version": "1.1.0",
4
+ "description": "External anchor providers for AgentOS provenance — blockchain, WORM storage, and transparency log integrations",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./manifest.json": "./manifest.json",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "test:coverage": "vitest run --coverage",
22
+ "lint": "eslint src --ext .ts",
23
+ "typecheck": "tsc --noEmit",
24
+ "docs": "typedoc --out docs src/index.ts",
25
+ "clean": "rimraf dist"
26
+ },
27
+ "keywords": [
28
+ "agentos",
29
+ "extension",
30
+ "provenance",
31
+ "anchor",
32
+ "blockchain",
33
+ "ethereum",
34
+ "opentimestamps",
35
+ "rekor",
36
+ "sigstore",
37
+ "worm",
38
+ "s3-object-lock",
39
+ "transparency-log"
40
+ ],
41
+ "author": {
42
+ "name": "Framers AI",
43
+ "email": "team@frame.dev",
44
+ "url": "https://frame.dev"
45
+ },
46
+ "contributors": [
47
+ {
48
+ "name": "Johnny Dunn",
49
+ "email": "johnnyfived@protonmail.com",
50
+ "url": "https://github.com/jddunn"
51
+ }
52
+ ],
53
+ "license": "MIT",
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/framersai/agentos-extensions.git",
57
+ "directory": "registry/curated/provenance/anchor-providers"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ },
62
+ "peerDependencies": {
63
+ "@framers/agentos": "^0.1.0",
64
+ "@aws-sdk/client-s3": "^3.0.0",
65
+ "@solana/web3.js": "^1.0.0",
66
+ "bs58": "^5.0.0",
67
+ "ethers": "^6.0.0",
68
+ "opentimestamps": "^0.4.0",
69
+ "sigstore": "^2.0.0"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "@aws-sdk/client-s3": {
73
+ "optional": true
74
+ },
75
+ "@solana/web3.js": {
76
+ "optional": true
77
+ },
78
+ "bs58": {
79
+ "optional": true
80
+ },
81
+ "ethers": {
82
+ "optional": true
83
+ },
84
+ "opentimestamps": {
85
+ "optional": true
86
+ },
87
+ "sigstore": {
88
+ "optional": true
89
+ }
90
+ },
91
+ "devDependencies": {
92
+ "@framers/agentos": "^0.1.0",
93
+ "@types/node": "^20.12.12",
94
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
95
+ "@typescript-eslint/parser": "^8.0.0",
96
+ "@vitest/coverage-v8": "^1.6.0",
97
+ "eslint": "^9.11.0",
98
+ "rimraf": "^5.0.7",
99
+ "typedoc": "^0.25.13",
100
+ "typescript": "^5.4.5",
101
+ "vitest": "^1.6.0"
102
+ }
103
+ }
package/src/index.ts ADDED
@@ -0,0 +1,59 @@
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
+
33
+ // Registry
34
+ export { registerExtensionProviders } from './register.js';
35
+
36
+ // Providers
37
+ export { WormSnapshotProvider } from './providers/WormSnapshotProvider.js';
38
+ export type { WormSnapshotProviderConfig } from './providers/WormSnapshotProvider.js';
39
+
40
+ export { RekorProvider } from './providers/RekorProvider.js';
41
+ export type { RekorProviderConfig } from './providers/RekorProvider.js';
42
+
43
+ export { OpenTimestampsProvider } from './providers/OpenTimestampsProvider.js';
44
+ export type { OpenTimestampsProviderConfig } from './providers/OpenTimestampsProvider.js';
45
+
46
+ export { EthereumProvider } from './providers/EthereumProvider.js';
47
+ export type { EthereumProviderConfig } from './providers/EthereumProvider.js';
48
+
49
+ export { SolanaProvider } from './providers/SolanaProvider.js';
50
+ export type { SolanaProviderConfig } from './providers/SolanaProvider.js';
51
+
52
+ // Shared types
53
+ export type { BaseProviderConfig } from './types.js';
54
+ export { resolveBaseConfig } from './types.js';
55
+
56
+ // Utilities
57
+ export { fetchWithRetry } from './utils/http-client.js';
58
+ export type { HttpRequestOptions } from './utils/http-client.js';
59
+ export { canonicalizeAnchor, hashCanonicalAnchor } from './utils/serialization.js';
@@ -0,0 +1,87 @@
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
+
12
+ import type { AnchorProvider, AnchorRecord, AnchorProviderResult, ProofLevel } from '@framers/agentos';
13
+ import type { BaseProviderConfig } from '../types.js';
14
+ import { resolveBaseConfig } from '../types.js';
15
+ import { hashCanonicalAnchor } from '../utils/serialization.js';
16
+
17
+ export interface EthereumProviderConfig extends BaseProviderConfig {
18
+ /** JSON-RPC endpoint URL. */
19
+ rpcUrl: string;
20
+ /** Contract address for anchor storage (optional — can use raw calldata tx). */
21
+ contractAddress?: string;
22
+ /** Private key hex for signing transactions. */
23
+ signerPrivateKey?: string;
24
+ /** Chain ID. Default: 1 (mainnet). */
25
+ chainId?: number;
26
+ /** Gas limit override. Default: auto-estimate. */
27
+ gasLimit?: number;
28
+ }
29
+
30
+ export class EthereumProvider implements AnchorProvider {
31
+ readonly id = 'ethereum';
32
+ readonly name = 'Ethereum On-Chain Anchor';
33
+ readonly proofLevel: ProofLevel = 'publicly-timestamped';
34
+
35
+ private readonly config: EthereumProviderConfig;
36
+ private readonly baseConfig: Required<BaseProviderConfig>;
37
+
38
+ constructor(config: EthereumProviderConfig) {
39
+ this.config = {
40
+ chainId: 1,
41
+ ...config,
42
+ };
43
+ this.baseConfig = resolveBaseConfig(config);
44
+ }
45
+
46
+ async publish(anchor: AnchorRecord): Promise<AnchorProviderResult> {
47
+ // TODO: Implement using ethers.js or viem
48
+ //
49
+ // Implementation outline:
50
+ // 1. Compute SHA-256 of canonical anchor: hashCanonicalAnchor(anchor)
51
+ // 2. Create ethers.JsonRpcProvider(this.config.rpcUrl)
52
+ // 3. Create ethers.Wallet(this.config.signerPrivateKey, provider)
53
+ // 4. If contractAddress is set:
54
+ // - ABI-encode call to `anchor(bytes32 merkleRoot)` on the contract
55
+ // - Send contract transaction
56
+ // 5. If no contractAddress (raw calldata):
57
+ // - Send self-transfer with 0x + anchorHash as calldata
58
+ // 6. Wait for transaction receipt (1 confirmation)
59
+ // 7. Return { success: true, externalRef: `eth:${chainId}:${txHash}`,
60
+ // metadata: { blockNumber, blockHash, gasUsed, chainId } }
61
+ try {
62
+ const _hash = await hashCanonicalAnchor(anchor);
63
+ throw new Error(
64
+ 'EthereumProvider is not yet implemented. ' +
65
+ 'Install ethers.js and implement the Ethereum on-chain anchor integration.',
66
+ );
67
+ } catch (e: unknown) {
68
+ return {
69
+ providerId: this.id,
70
+ success: false,
71
+ error: e instanceof Error ? e.message : String(e),
72
+ };
73
+ }
74
+ }
75
+
76
+ async verify(anchor: AnchorRecord): Promise<boolean> {
77
+ // TODO: Parse txHash from externalRef, fetch transaction receipt,
78
+ // decode calldata, compare with anchor hash
79
+ if (!anchor.externalRef) return false;
80
+ console.warn('[EthereumProvider] verify() is not yet implemented');
81
+ return false;
82
+ }
83
+
84
+ async dispose(): Promise<void> {
85
+ // TODO: Disconnect provider if persistent connection was established
86
+ }
87
+ }