repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | /** |
| #2 | * Social Client Factory |
| #3 | * |
| #4 | * Creates a SocialClient for the automaton runtime. |
| #5 | * Self-contained: uses viem for signing and fetch for HTTP. |
| #6 | */ |
| #7 | |
| #8 | import { |
| #9 | type PrivateKeyAccount, |
| #10 | keccak256, |
| #11 | toBytes, |
| #12 | } from "viem"; |
| #13 | import type { SocialClientInterface, InboxMessage } from "../types.js"; |
| #14 | |
| #15 | /** |
| #16 | * Create a SocialClient wired to the agent's wallet. |
| #17 | */ |
| #18 | export function createSocialClient( |
| #19 | relayUrl: string, |
| #20 | account: PrivateKeyAccount, |
| #21 | ): SocialClientInterface { |
| #22 | const baseUrl = relayUrl.replace(/\/$/, ""); |
| #23 | |
| #24 | return { |
| #25 | send: async ( |
| #26 | to: string, |
| #27 | content: string, |
| #28 | replyTo?: string, |
| #29 | ): Promise<{ id: string }> => { |
| #30 | const signedAt = new Date().toISOString(); |
| #31 | const contentHash = keccak256(toBytes(content)); |
| #32 | const canonical = `CLAWD Runtime:send:${to.toLowerCase()}:${contentHash}:${signedAt}`; |
| #33 | const signature = await account.signMessage({ message: canonical }); |
| #34 | |
| #35 | const res = await fetch(`${baseUrl}/v1/messages`, { |
| #36 | method: "POST", |
| #37 | headers: { "Content-Type": "application/json" }, |
| #38 | body: JSON.stringify({ |
| #39 | from: account.address.toLowerCase(), |
| #40 | to: to.toLowerCase(), |
| #41 | content, |
| #42 | signature, |
| #43 | signed_at: signedAt, |
| #44 | reply_to: replyTo, |
| #45 | }), |
| #46 | }); |
| #47 | |
| #48 | if (!res.ok) { |
| #49 | const err = await res.json().catch(() => ({ error: res.statusText })); |
| #50 | throw new Error( |
| #51 | `Send failed (${res.status}): ${(err as any).error || res.statusText}`, |
| #52 | ); |
| #53 | } |
| #54 | |
| #55 | const data = (await res.json()) as { id: string }; |
| #56 | return { id: data.id }; |
| #57 | }, |
| #58 | |
| #59 | poll: async ( |
| #60 | cursor?: string, |
| #61 | limit?: number, |
| #62 | ): Promise<{ messages: InboxMessage[]; nextCursor?: string }> => { |
| #63 | const timestamp = new Date().toISOString(); |
| #64 | const canonical = `CLAWD Runtime:poll:${account.address.toLowerCase()}:${timestamp}`; |
| #65 | const signature = await account.signMessage({ message: canonical }); |
| #66 | |
| #67 | const res = await fetch(`${baseUrl}/v1/messages/poll`, { |
| #68 | method: "POST", |
| #69 | headers: { |
| #70 | "Content-Type": "application/json", |
| #71 | "X-Wallet-Address": account.address.toLowerCase(), |
| #72 | "X-Signature": signature, |
| #73 | "X-Timestamp": timestamp, |
| #74 | }, |
| #75 | body: JSON.stringify({ cursor, limit }), |
| #76 | }); |
| #77 | |
| #78 | if (!res.ok) { |
| #79 | const err = await res.json().catch(() => ({ error: res.statusText })); |
| #80 | throw new Error( |
| #81 | `Poll failed (${res.status}): ${(err as any).error || res.statusText}`, |
| #82 | ); |
| #83 | } |
| #84 | |
| #85 | const data = (await res.json()) as { |
| #86 | messages: Array<{ |
| #87 | id: string; |
| #88 | from: string; |
| #89 | to: string; |
| #90 | content: string; |
| #91 | signedAt: string; |
| #92 | createdAt: string; |
| #93 | replyTo?: string; |
| #94 | }>; |
| #95 | next_cursor?: string; |
| #96 | }; |
| #97 | |
| #98 | return { |
| #99 | messages: data.messages.map((m) => ({ |
| #100 | id: m.id, |
| #101 | from: m.from, |
| #102 | to: m.to, |
| #103 | content: m.content, |
| #104 | signedAt: m.signedAt, |
| #105 | createdAt: m.createdAt, |
| #106 | replyTo: m.replyTo, |
| #107 | })), |
| #108 | nextCursor: data.next_cursor, |
| #109 | }; |
| #110 | }, |
| #111 | |
| #112 | unreadCount: async (): Promise<number> => { |
| #113 | const timestamp = new Date().toISOString(); |
| #114 | const canonical = `CLAWD Runtime:poll:${account.address.toLowerCase()}:${timestamp}`; |
| #115 | const signature = await account.signMessage({ message: canonical }); |
| #116 | |
| #117 | const res = await fetch(`${baseUrl}/v1/messages/count`, { |
| #118 | method: "GET", |
| #119 | headers: { |
| #120 | "X-Wallet-Address": account.address.toLowerCase(), |
| #121 | "X-Signature": signature, |
| #122 | "X-Timestamp": timestamp, |
| #123 | }, |
| #124 | }); |
| #125 | |
| #126 | if (!res.ok) return 0; |
| #127 | |
| #128 | const data = (await res.json()) as { unread: number }; |
| #129 | return data.unread; |
| #130 | }, |
| #131 | }; |
| #132 | } |
| #133 |