hawk-names 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Agent trust for the x402 economy: resolve a .hawk name, check the four
3
+ * HIP-1 verification proofs, and only then let money move.
4
+ *
5
+ * The x402 client itself stays out of this package — pass any
6
+ * payment-capable fetch (for example `@x402/fetch`'s wrapped fetch) and
7
+ * this module gates it behind verification. Zero new dependencies.
8
+ */
9
+ export type AgentChecks = {
10
+ registered: boolean;
11
+ rootActive: boolean;
12
+ addressSet: boolean;
13
+ primaryMatch: boolean;
14
+ };
15
+ export type AgentInfo = {
16
+ name: string;
17
+ node: `0x${string}`;
18
+ verified: boolean;
19
+ checks: AgentChecks;
20
+ address: `0x${string}` | null;
21
+ primaryName: string | null;
22
+ capabilities: string[];
23
+ url: string | null;
24
+ records: Record<string, string>;
25
+ operator: {
26
+ name: string;
27
+ address: `0x${string}` | null;
28
+ } | null;
29
+ };
30
+ export declare class AgentNotVerifiedError extends Error {
31
+ readonly agent: AgentInfo;
32
+ constructor(agent: AgentInfo);
33
+ }
34
+ /** Fetch an agent's verification report from the hawk verify API. */
35
+ export declare function resolveAgent(name: string, opts?: {
36
+ apiUrl?: string;
37
+ fetch?: typeof fetch;
38
+ }): Promise<AgentInfo>;
39
+ /** Resolve an agent and throw unless all four verification checks pass. */
40
+ export declare function requireVerifiedAgent(name: string, opts?: {
41
+ apiUrl?: string;
42
+ fetch?: typeof fetch;
43
+ }): Promise<AgentInfo>;
44
+ export type VerifiedFetch = (agentName: string, path?: string, init?: RequestInit) => Promise<Response>;
45
+ /**
46
+ * Gate a payment-capable fetch behind hawk verification.
47
+ *
48
+ * `payFetch` is any fetch-shaped function — typically the result of
49
+ * `@x402/fetch`'s `wrapFetchWithPaymentFromConfig(fetch, …)`, so 402
50
+ * challenges from the agent's endpoint are paid automatically, but ONLY
51
+ * after the agent proved who it is:
52
+ *
53
+ * ```ts
54
+ * import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
55
+ * import { ExactEvmScheme } from "@x402/evm";
56
+ * import { verifiedFetch } from "hawk-names/agents";
57
+ *
58
+ * const pay = wrapFetchWithPaymentFromConfig(fetch, {
59
+ * schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
60
+ * });
61
+ * const callAgent = verifiedFetch(pay);
62
+ * const res = await callAgent("quotes.acme.hawk", "/price?pair=ETH-USDC");
63
+ * ```
64
+ *
65
+ * The agent's base URL comes from its on-chain `url` record; `path` is
66
+ * appended. Refuses to call agents whose verification fails.
67
+ */
68
+ export declare function verifiedFetch(payFetch: typeof fetch, opts?: {
69
+ apiUrl?: string;
70
+ }): VerifiedFetch;
71
+ /**
72
+ * The address money should go to for a named agent — verified first.
73
+ * Use this when constructing payments yourself (x402 payTo, transfers).
74
+ */
75
+ export declare function verifiedPayTo(name: string, opts?: {
76
+ apiUrl?: string;
77
+ fetch?: typeof fetch;
78
+ }): Promise<`0x${string}`>;
package/dist/agents.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Agent trust for the x402 economy: resolve a .hawk name, check the four
3
+ * HIP-1 verification proofs, and only then let money move.
4
+ *
5
+ * The x402 client itself stays out of this package — pass any
6
+ * payment-capable fetch (for example `@x402/fetch`'s wrapped fetch) and
7
+ * this module gates it behind verification. Zero new dependencies.
8
+ */
9
+ const DEFAULT_API = "https://api.dothawk.xyz";
10
+ export class AgentNotVerifiedError extends Error {
11
+ agent;
12
+ constructor(agent) {
13
+ const failed = Object.entries(agent.checks)
14
+ .filter(([, ok]) => !ok)
15
+ .map(([k]) => k)
16
+ .join(", ");
17
+ super(`${agent.name} is not a verified agent (failing: ${failed || "unknown"})`);
18
+ this.name = "AgentNotVerifiedError";
19
+ this.agent = agent;
20
+ }
21
+ }
22
+ /** Fetch an agent's verification report from the hawk verify API. */
23
+ export async function resolveAgent(name, opts = {}) {
24
+ const api = (opts.apiUrl ?? DEFAULT_API).replace(/\/$/, "");
25
+ const f = opts.fetch ?? fetch;
26
+ const res = await f(`${api}/verify/${encodeURIComponent(name)}`);
27
+ if (!res.ok) {
28
+ throw new Error(`hawk verify API: HTTP ${res.status} for ${name}`);
29
+ }
30
+ const body = (await res.json());
31
+ return {
32
+ name: body.name,
33
+ node: body.node,
34
+ verified: body.verified,
35
+ checks: body.checks,
36
+ address: body.address,
37
+ primaryName: body.primaryName,
38
+ capabilities: body.agent?.capabilities ?? [],
39
+ url: body.agent?.url ?? null,
40
+ records: body.records ?? {},
41
+ operator: body.operator
42
+ ? { name: body.operator.name, address: body.operator.address }
43
+ : null,
44
+ };
45
+ }
46
+ /** Resolve an agent and throw unless all four verification checks pass. */
47
+ export async function requireVerifiedAgent(name, opts = {}) {
48
+ const agent = await resolveAgent(name, opts);
49
+ if (!agent.verified)
50
+ throw new AgentNotVerifiedError(agent);
51
+ return agent;
52
+ }
53
+ /**
54
+ * Gate a payment-capable fetch behind hawk verification.
55
+ *
56
+ * `payFetch` is any fetch-shaped function — typically the result of
57
+ * `@x402/fetch`'s `wrapFetchWithPaymentFromConfig(fetch, …)`, so 402
58
+ * challenges from the agent's endpoint are paid automatically, but ONLY
59
+ * after the agent proved who it is:
60
+ *
61
+ * ```ts
62
+ * import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
63
+ * import { ExactEvmScheme } from "@x402/evm";
64
+ * import { verifiedFetch } from "hawk-names/agents";
65
+ *
66
+ * const pay = wrapFetchWithPaymentFromConfig(fetch, {
67
+ * schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
68
+ * });
69
+ * const callAgent = verifiedFetch(pay);
70
+ * const res = await callAgent("quotes.acme.hawk", "/price?pair=ETH-USDC");
71
+ * ```
72
+ *
73
+ * The agent's base URL comes from its on-chain `url` record; `path` is
74
+ * appended. Refuses to call agents whose verification fails.
75
+ */
76
+ export function verifiedFetch(payFetch, opts = {}) {
77
+ return async (agentName, path = "", init) => {
78
+ const agent = await requireVerifiedAgent(agentName, opts);
79
+ if (!agent.url) {
80
+ throw new Error(`${agent.name} is verified but publishes no url record to call`);
81
+ }
82
+ const base = agent.url.replace(/\/$/, "");
83
+ const target = path ? `${base}${path.startsWith("/") ? "" : "/"}${path}` : base;
84
+ return payFetch(target, init);
85
+ };
86
+ }
87
+ /**
88
+ * The address money should go to for a named agent — verified first.
89
+ * Use this when constructing payments yourself (x402 payTo, transfers).
90
+ */
91
+ export async function verifiedPayTo(name, opts = {}) {
92
+ const agent = await requireVerifiedAgent(name, opts);
93
+ if (!agent.address) {
94
+ throw new Error(`${agent.name} has no address record`);
95
+ }
96
+ return agent.address;
97
+ }
package/dist/index.d.ts CHANGED
@@ -4,3 +4,4 @@ export { getHawkName, getHawkAddress, getHawkText, getHawkAvatar, } from "./acti
4
4
  export { HAWK_NODE, REVERSE_RECORD_NONE, REVERSE_RECORD_CHAIN, REVERSE_RECORD_DEFAULT, SECONDS_PER_YEAR, MIN_REGISTRATION_DURATION_MAINNET, MAX_REGISTRATION_DURATION, type Registration, makeRegistration, makeCommitment, randomSecret, hawkNode, hawkTokenId, validateLabel, } from "./registration.js";
5
5
  export { normalize, namehash, labelhash } from "viem/ens";
6
6
  export * from "./generated/abis.js";
7
+ export * from "./agents.js";
package/dist/index.js CHANGED
@@ -11,3 +11,4 @@ export { getHawkName, getHawkAddress, getHawkText, getHawkAvatar, } from "./acti
11
11
  export { HAWK_NODE, REVERSE_RECORD_NONE, REVERSE_RECORD_CHAIN, REVERSE_RECORD_DEFAULT, SECONDS_PER_YEAR, MIN_REGISTRATION_DURATION_MAINNET, MAX_REGISTRATION_DURATION, makeRegistration, makeCommitment, randomSecret, hawkNode, hawkTokenId, validateLabel, } from "./registration.js";
12
12
  export { normalize, namehash, labelhash } from "viem/ens";
13
13
  export * from "./generated/abis.js";
14
+ export * from "./agents.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hawk-names",
3
- "version": "0.1.1",
4
- "description": "Resolve and register .hawk names on Base ENS-standard resolution with a one-line viem config.",
3
+ "version": "0.2.0",
4
+ "description": "Resolve and register .hawk names on Base \u2014 ENS-standard resolution with a one-line viem config.",
5
5
  "license": "MIT",
6
6
  "author": "dotrobinxyz",
7
7
  "homepage": "https://docs.dothawk.xyz",
@@ -20,6 +20,10 @@
20
20
  ".": {
21
21
  "types": "./dist/index.d.ts",
22
22
  "default": "./dist/index.js"
23
+ },
24
+ "./agents": {
25
+ "types": "./dist/agents.d.ts",
26
+ "default": "./dist/agents.js"
23
27
  }
24
28
  },
25
29
  "files": [
@@ -46,4 +50,4 @@
46
50
  "naming",
47
51
  "viem"
48
52
  ]
49
- }
53
+ }
package/src/agents.ts ADDED
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Agent trust for the x402 economy: resolve a .hawk name, check the four
3
+ * HIP-1 verification proofs, and only then let money move.
4
+ *
5
+ * The x402 client itself stays out of this package — pass any
6
+ * payment-capable fetch (for example `@x402/fetch`'s wrapped fetch) and
7
+ * this module gates it behind verification. Zero new dependencies.
8
+ */
9
+
10
+ const DEFAULT_API = "https://api.dothawk.xyz";
11
+
12
+ export type AgentChecks = {
13
+ registered: boolean;
14
+ rootActive: boolean;
15
+ addressSet: boolean;
16
+ primaryMatch: boolean;
17
+ };
18
+
19
+ export type AgentInfo = {
20
+ name: string;
21
+ node: `0x${string}`;
22
+ verified: boolean;
23
+ checks: AgentChecks;
24
+ address: `0x${string}` | null;
25
+ primaryName: string | null;
26
+ capabilities: string[];
27
+ url: string | null;
28
+ records: Record<string, string>;
29
+ operator: { name: string; address: `0x${string}` | null } | null;
30
+ };
31
+
32
+ export class AgentNotVerifiedError extends Error {
33
+ readonly agent: AgentInfo;
34
+
35
+ constructor(agent: AgentInfo) {
36
+ const failed = Object.entries(agent.checks)
37
+ .filter(([, ok]) => !ok)
38
+ .map(([k]) => k)
39
+ .join(", ");
40
+ super(
41
+ `${agent.name} is not a verified agent (failing: ${failed || "unknown"})`,
42
+ );
43
+ this.name = "AgentNotVerifiedError";
44
+ this.agent = agent;
45
+ }
46
+ }
47
+
48
+ /** Fetch an agent's verification report from the hawk verify API. */
49
+ export async function resolveAgent(
50
+ name: string,
51
+ opts: { apiUrl?: string; fetch?: typeof fetch } = {},
52
+ ): Promise<AgentInfo> {
53
+ const api = (opts.apiUrl ?? DEFAULT_API).replace(/\/$/, "");
54
+ const f = opts.fetch ?? fetch;
55
+ const res = await f(`${api}/verify/${encodeURIComponent(name)}`);
56
+ if (!res.ok) {
57
+ throw new Error(`hawk verify API: HTTP ${res.status} for ${name}`);
58
+ }
59
+ const body = (await res.json()) as {
60
+ name: string;
61
+ node: `0x${string}`;
62
+ verified: boolean;
63
+ checks: AgentChecks;
64
+ address: `0x${string}` | null;
65
+ primaryName: string | null;
66
+ records: Record<string, string>;
67
+ agent: { capabilities: string[]; url: string | null };
68
+ operator: { name: string; address: `0x${string}` | null } | null;
69
+ };
70
+ return {
71
+ name: body.name,
72
+ node: body.node,
73
+ verified: body.verified,
74
+ checks: body.checks,
75
+ address: body.address,
76
+ primaryName: body.primaryName,
77
+ capabilities: body.agent?.capabilities ?? [],
78
+ url: body.agent?.url ?? null,
79
+ records: body.records ?? {},
80
+ operator: body.operator
81
+ ? { name: body.operator.name, address: body.operator.address }
82
+ : null,
83
+ };
84
+ }
85
+
86
+ /** Resolve an agent and throw unless all four verification checks pass. */
87
+ export async function requireVerifiedAgent(
88
+ name: string,
89
+ opts: { apiUrl?: string; fetch?: typeof fetch } = {},
90
+ ): Promise<AgentInfo> {
91
+ const agent = await resolveAgent(name, opts);
92
+ if (!agent.verified) throw new AgentNotVerifiedError(agent);
93
+ return agent;
94
+ }
95
+
96
+ export type VerifiedFetch = (
97
+ agentName: string,
98
+ path?: string,
99
+ init?: RequestInit,
100
+ ) => Promise<Response>;
101
+
102
+ /**
103
+ * Gate a payment-capable fetch behind hawk verification.
104
+ *
105
+ * `payFetch` is any fetch-shaped function — typically the result of
106
+ * `@x402/fetch`'s `wrapFetchWithPaymentFromConfig(fetch, …)`, so 402
107
+ * challenges from the agent's endpoint are paid automatically, but ONLY
108
+ * after the agent proved who it is:
109
+ *
110
+ * ```ts
111
+ * import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
112
+ * import { ExactEvmScheme } from "@x402/evm";
113
+ * import { verifiedFetch } from "hawk-names/agents";
114
+ *
115
+ * const pay = wrapFetchWithPaymentFromConfig(fetch, {
116
+ * schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
117
+ * });
118
+ * const callAgent = verifiedFetch(pay);
119
+ * const res = await callAgent("quotes.acme.hawk", "/price?pair=ETH-USDC");
120
+ * ```
121
+ *
122
+ * The agent's base URL comes from its on-chain `url` record; `path` is
123
+ * appended. Refuses to call agents whose verification fails.
124
+ */
125
+ export function verifiedFetch(
126
+ payFetch: typeof fetch,
127
+ opts: { apiUrl?: string } = {},
128
+ ): VerifiedFetch {
129
+ return async (agentName, path = "", init) => {
130
+ const agent = await requireVerifiedAgent(agentName, opts);
131
+ if (!agent.url) {
132
+ throw new Error(
133
+ `${agent.name} is verified but publishes no url record to call`,
134
+ );
135
+ }
136
+ const base = agent.url.replace(/\/$/, "");
137
+ const target = path ? `${base}${path.startsWith("/") ? "" : "/"}${path}` : base;
138
+ return payFetch(target, init);
139
+ };
140
+ }
141
+
142
+ /**
143
+ * The address money should go to for a named agent — verified first.
144
+ * Use this when constructing payments yourself (x402 payTo, transfers).
145
+ */
146
+ export async function verifiedPayTo(
147
+ name: string,
148
+ opts: { apiUrl?: string; fetch?: typeof fetch } = {},
149
+ ): Promise<`0x${string}`> {
150
+ const agent = await requireVerifiedAgent(name, opts);
151
+ if (!agent.address) {
152
+ throw new Error(`${agent.name} has no address record`);
153
+ }
154
+ return agent.address;
155
+ }
package/src/index.ts CHANGED
@@ -46,3 +46,4 @@ export {
46
46
  export { normalize, namehash, labelhash } from "viem/ens";
47
47
 
48
48
  export * from "./generated/abis.js";
49
+ export * from "./agents.js";