@naulon/wayfarer 0.1.1

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 (86) hide show
  1. package/README.md +39 -0
  2. package/dist/agent.d.ts +77 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +235 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/allocation.d.ts +36 -0
  7. package/dist/allocation.d.ts.map +1 -0
  8. package/dist/allocation.js +45 -0
  9. package/dist/allocation.js.map +1 -0
  10. package/dist/appraise.d.ts +3 -0
  11. package/dist/appraise.d.ts.map +1 -0
  12. package/dist/appraise.js +60 -0
  13. package/dist/appraise.js.map +1 -0
  14. package/dist/buyer.d.ts +195 -0
  15. package/dist/buyer.d.ts.map +1 -0
  16. package/dist/buyer.js +254 -0
  17. package/dist/buyer.js.map +1 -0
  18. package/dist/decide.d.ts +115 -0
  19. package/dist/decide.d.ts.map +1 -0
  20. package/dist/decide.js +206 -0
  21. package/dist/decide.js.map +1 -0
  22. package/dist/discover.d.ts +10 -0
  23. package/dist/discover.d.ts.map +1 -0
  24. package/dist/discover.js +5 -0
  25. package/dist/discover.js.map +1 -0
  26. package/dist/discovery.d.ts +26 -0
  27. package/dist/discovery.d.ts.map +1 -0
  28. package/dist/discovery.js +93 -0
  29. package/dist/discovery.js.map +1 -0
  30. package/dist/gateway.d.ts +117 -0
  31. package/dist/gateway.d.ts.map +1 -0
  32. package/dist/gateway.js +187 -0
  33. package/dist/gateway.js.map +1 -0
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +19 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/lib.d.ts +40 -0
  39. package/dist/lib.d.ts.map +1 -0
  40. package/dist/lib.js +44 -0
  41. package/dist/lib.js.map +1 -0
  42. package/dist/licenseStore.d.ts +56 -0
  43. package/dist/licenseStore.d.ts.map +1 -0
  44. package/dist/licenseStore.js +79 -0
  45. package/dist/licenseStore.js.map +1 -0
  46. package/dist/memo.d.ts +43 -0
  47. package/dist/memo.d.ts.map +1 -0
  48. package/dist/memo.js +102 -0
  49. package/dist/memo.js.map +1 -0
  50. package/dist/origin-policy.d.ts +74 -0
  51. package/dist/origin-policy.d.ts.map +1 -0
  52. package/dist/origin-policy.js +88 -0
  53. package/dist/origin-policy.js.map +1 -0
  54. package/dist/paidFetch.d.ts +14 -0
  55. package/dist/paidFetch.d.ts.map +1 -0
  56. package/dist/paidFetch.js +93 -0
  57. package/dist/paidFetch.js.map +1 -0
  58. package/dist/pay.d.ts +3 -0
  59. package/dist/pay.d.ts.map +1 -0
  60. package/dist/pay.js +82 -0
  61. package/dist/pay.js.map +1 -0
  62. package/dist/pop.d.ts +8 -0
  63. package/dist/pop.d.ts.map +1 -0
  64. package/dist/pop.js +25 -0
  65. package/dist/pop.js.map +1 -0
  66. package/dist/rail.d.ts +18 -0
  67. package/dist/rail.d.ts.map +1 -0
  68. package/dist/rail.js +73 -0
  69. package/dist/rail.js.map +1 -0
  70. package/dist/rss.d.ts +38 -0
  71. package/dist/rss.d.ts.map +1 -0
  72. package/dist/rss.js +110 -0
  73. package/dist/rss.js.map +1 -0
  74. package/dist/sign.d.ts +13 -0
  75. package/dist/sign.d.ts.map +1 -0
  76. package/dist/sign.js +52 -0
  77. package/dist/sign.js.map +1 -0
  78. package/dist/types.d.ts +75 -0
  79. package/dist/types.d.ts.map +1 -0
  80. package/dist/types.js +2 -0
  81. package/dist/types.js.map +1 -0
  82. package/dist/wallet.d.ts +12 -0
  83. package/dist/wallet.d.ts.map +1 -0
  84. package/dist/wallet.js +46 -0
  85. package/dist/wallet.js.map +1 -0
  86. package/package.json +42 -0
package/dist/rss.js ADDED
@@ -0,0 +1,110 @@
1
+ const ENTITIES = {
2
+ amp: "&",
3
+ lt: "<",
4
+ gt: ">",
5
+ quot: '"',
6
+ apos: "'",
7
+ "#39": "'",
8
+ };
9
+ /** Decode the handful of XML entities a feed actually emits (+ numeric refs). */
10
+ function decodeEntities(s) {
11
+ return s.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (whole, code) => {
12
+ if (code[0] === "#") {
13
+ const cp = code[1] === "x" || code[1] === "X"
14
+ ? Number.parseInt(code.slice(2), 16)
15
+ : Number.parseInt(code.slice(1), 10);
16
+ return Number.isFinite(cp) ? String.fromCodePoint(cp) : whole;
17
+ }
18
+ return ENTITIES[code] ?? whole;
19
+ });
20
+ }
21
+ /** Strip a `<![CDATA[ ... ]]>` wrapper if present, then trim. */
22
+ function unwrap(raw) {
23
+ const cdata = raw.match(/^\s*<!\[CDATA\[([\s\S]*?)\]\]>\s*$/);
24
+ return (cdata ? cdata[1] : raw).trim();
25
+ }
26
+ /** Inner text of the first `<tag …>…</tag>` in `block`, decoded. "" if absent. */
27
+ function tag(block, name) {
28
+ const re = new RegExp(`<${name}(?:\\s[^>]*)?>([\\s\\S]*?)</${name}>`, "i");
29
+ const m = block.match(re);
30
+ if (!m)
31
+ return "";
32
+ const inner = unwrap(m[1]);
33
+ // CDATA content is literal; only decode entities outside a CDATA section.
34
+ return /^\s*<!\[CDATA\[/.test(m[1]) ? inner : decodeEntities(inner);
35
+ }
36
+ /** `href` of a self-closing `<link … href="…"/>` (Atom-style), decoded. "" if absent. */
37
+ function linkHref(block) {
38
+ const m = block.match(/<link\b[^>]*\bhref=["']([^"']+)["'][^>]*\/?>/i);
39
+ return m ? decodeEntities(m[1]) : "";
40
+ }
41
+ /** Parse an RSS 2.0 (or Atom-ish) document into its items. Lenient by design. */
42
+ export function parseRss(xml) {
43
+ const items = [];
44
+ for (const m of xml.matchAll(/<(?:item|entry)\b[\s\S]*?<\/(?:item|entry)>/gi)) {
45
+ const block = m[0];
46
+ const link = tag(block, "link") || linkHref(block);
47
+ const item = {
48
+ title: tag(block, "title"),
49
+ link,
50
+ description: tag(block, "description") || tag(block, "summary"),
51
+ guid: tag(block, "guid") || undefined,
52
+ };
53
+ const body = tag(block, "content:encoded");
54
+ if (body)
55
+ item.contentEncoded = body;
56
+ items.push(item);
57
+ }
58
+ return items;
59
+ }
60
+ /** Slug = the last non-empty path segment of the item's link (or guid). */
61
+ export function slugFromLink(link) {
62
+ if (!link)
63
+ return "";
64
+ let path = link;
65
+ try {
66
+ path = new URL(link).pathname;
67
+ }
68
+ catch {
69
+ // Relative or malformed — fall back to the raw string, sans query/hash.
70
+ path = link.split(/[?#]/)[0];
71
+ }
72
+ const segs = path.split("/").filter(Boolean);
73
+ const last = segs[segs.length - 1] ?? "";
74
+ try {
75
+ return decodeURIComponent(last);
76
+ }
77
+ catch {
78
+ return last;
79
+ }
80
+ }
81
+ /**
82
+ * The teaser boundary — what the agent may read for FREE, pre-payment.
83
+ *
84
+ * This is a product decision, not a parsing detail: a feed that ships the full
85
+ * body in `<content:encoded>` would let the agent bypass the toll at discovery.
86
+ * So we read the teaser field only and never the body, regardless of what the
87
+ * feed includes. Keeping it a named function makes that line explicit and easy
88
+ * to retune per publisher.
89
+ */
90
+ export function extractTeaser(item) {
91
+ return item.description.trim();
92
+ }
93
+ /** Map a parsed item to a free-teaser Candidate (slug + title + teaser). */
94
+ export function rssItemToCandidate(item) {
95
+ return {
96
+ slug: slugFromLink(item.link || item.guid || ""),
97
+ title: item.title,
98
+ summary: extractTeaser(item),
99
+ // Carry the real feed link so pay/quote hit the publisher's actual URL shape
100
+ // (e.g. /articles/<slug>) instead of reconstructing /essays/<slug>.
101
+ url: item.link || undefined,
102
+ };
103
+ }
104
+ /** Full feed → candidates, dropping anything with no usable slug. */
105
+ export function rssToCandidates(xml) {
106
+ return parseRss(xml)
107
+ .map(rssItemToCandidate)
108
+ .filter((c) => c.slug.length > 0);
109
+ }
110
+ //# sourceMappingURL=rss.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rss.js","sourceRoot":"","sources":["../src/rss.ts"],"names":[],"mappings":"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"}
package/dist/sign.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ /** Test seam: forget the cached identity (pairs with shared's resetConfig). */
2
+ export declare function resetAgentIdentity(): void;
3
+ /** The three Web Bot Auth headers for a request to `url`, or null when the
4
+ * signing identity isn't configured. Signed per call — the ~1-minute validity
5
+ * window means a signature is never reusable across a slow run. */
6
+ export declare function botAuthHeadersFor(url: string): Record<string, string> | null;
7
+ /**
8
+ * fetch with the wayfarer's Web Bot Auth identity attached (when configured).
9
+ * Caller headers win on collision — not that anything else sets these — and an
10
+ * unconfigured agent falls through to the exact fetch it always made.
11
+ */
12
+ export declare function agentFetch(url: string, init?: RequestInit): Promise<Response>;
13
+ //# sourceMappingURL=sign.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAgCA,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;oEAEoE;AACpE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAK5E;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAKnF"}
package/dist/sign.js ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Web Bot Auth request signing (WBA slice 3) — the wayfarer as a signing agent.
3
+ *
4
+ * When the operator configures a signing identity (BOT_AUTH_SIGNING_KEY) and a
5
+ * directory host to advertise (BOT_AUTH_SIGNATURE_AGENT), every outbound
6
+ * wayfarer request carries the three RFC 9421 headers, so ANY Web-Bot-Auth
7
+ * verifier — our own gate, or a Cloudflare-fronted publisher — can prove who
8
+ * is calling instead of trusting the UA string. Unconfigured, `agentFetch` is
9
+ * a plain fetch: byte-identical headers, the same regression bar the gate's
10
+ * verifier holds for unsigned traffic.
11
+ */
12
+ import { botAuthKeyFromSeed, getConfig, signBotAuth } from "@naulon/shared";
13
+ /** Lazily resolved once per process; `undefined` = not yet looked at,
14
+ * `null` = signing not configured. */
15
+ let identity;
16
+ function resolveIdentity() {
17
+ if (identity !== undefined)
18
+ return identity;
19
+ const cfg = getConfig();
20
+ identity =
21
+ cfg.BOT_AUTH_SIGNING_KEY && cfg.BOT_AUTH_SIGNATURE_AGENT
22
+ ? { key: botAuthKeyFromSeed(cfg.BOT_AUTH_SIGNING_KEY), agent: cfg.BOT_AUTH_SIGNATURE_AGENT }
23
+ : null;
24
+ return identity;
25
+ }
26
+ /** Test seam: forget the cached identity (pairs with shared's resetConfig). */
27
+ export function resetAgentIdentity() {
28
+ identity = undefined;
29
+ }
30
+ /** The three Web Bot Auth headers for a request to `url`, or null when the
31
+ * signing identity isn't configured. Signed per call — the ~1-minute validity
32
+ * window means a signature is never reusable across a slow run. */
33
+ export function botAuthHeadersFor(url) {
34
+ const id = resolveIdentity();
35
+ if (!id)
36
+ return null;
37
+ const authority = new URL(url).host;
38
+ return { ...signBotAuth({ key: id.key, authority, tag: "web-bot-auth", agent: id.agent }) };
39
+ }
40
+ /**
41
+ * fetch with the wayfarer's Web Bot Auth identity attached (when configured).
42
+ * Caller headers win on collision — not that anything else sets these — and an
43
+ * unconfigured agent falls through to the exact fetch it always made.
44
+ */
45
+ export async function agentFetch(url, init) {
46
+ const signed = botAuthHeadersFor(url);
47
+ if (!signed)
48
+ return fetch(url, init);
49
+ const headers = { ...signed, ...(init?.headers ?? {}) };
50
+ return fetch(url, { ...init, headers });
51
+ }
52
+ //# sourceMappingURL=sign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAmB,MAAM,gBAAgB,CAAC;AAO7F;uCACuC;AACvC,IAAI,QAA0C,CAAC;AAE/C,SAAS,eAAe;IACtB,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC5C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,QAAQ;QACN,GAAG,CAAC,oBAAoB,IAAI,GAAG,CAAC,wBAAwB;YACtD,CAAC,CAAC,EAAE,GAAG,EAAE,kBAAkB,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,wBAAwB,EAAE;YAC5F,CAAC,CAAC,IAAI,CAAC;IACX,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB;IAChC,QAAQ,GAAG,SAAS,CAAC;AACvB,CAAC;AAED;;oEAEoE;AACpE,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;IAC7B,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACpC,OAAO,EAAE,GAAG,WAAW,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,IAAkB;IAC9D,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,EAAE,GAAG,CAAE,IAAI,EAAE,OAA8C,IAAI,EAAE,CAAC,EAAE,CAAC;IAChG,OAAO,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,75 @@
1
+ /** Wayfarer domain types — the shapes that flow through discover → … → ground. */
2
+ import type { Usdc } from "@naulon/shared";
3
+ /** An essay the agent could pay to read, before it has decided anything. */
4
+ export interface Candidate {
5
+ slug: string;
6
+ title: string;
7
+ /** Public teaser the agent reads for free to judge relevance. */
8
+ summary: string;
9
+ /**
10
+ * Publisher host this candidate is served from (e.g. `example.com`). Optional:
11
+ * the single-gate pipeline leaves it unset (one configured origin). Multi-gate
12
+ * discovery (the fleet directory) populates it, and the policy engine uses it
13
+ * for domain allow/deny + per-domain caps.
14
+ */
15
+ host?: string;
16
+ /**
17
+ * Canonical URL this candidate is served from — the real link a discovery source
18
+ * (RSS `<link>`, sitemap `<loc>`, catalog/directory `url`) already knows. When
19
+ * present, quote/pay use it VERBATIM. Absent ⇒ the pipeline falls back to
20
+ * `articleUrl(base, slug)` (the single-gate `/essays/<slug>` convention). Carrying
21
+ * the real URL is what lets one buyer pay any publisher's URL shape — `/articles/`,
22
+ * a custom domain, a query string — instead of reconstructing a fixed template.
23
+ */
24
+ url?: string;
25
+ /** Indicative read price (USDC) a fleet catalog may carry. Advisory — the 402 is the truth. */
26
+ priceUsdc?: number;
27
+ /** Indicative citation price (USDC). Advisory — the 402 is the truth. */
28
+ citationPriceUsdc?: number;
29
+ }
30
+ /** A candidate after the tollgate has quoted a price for it. The author split is
31
+ * the seller's concern (recorded on the event); the buyer only needs the price. */
32
+ export interface PricedCandidate extends Candidate {
33
+ price: Usdc;
34
+ }
35
+ /** A candidate after appraisal — how useful it looks for the topic. */
36
+ export interface AppraisedCandidate extends PricedCandidate {
37
+ /** 0..1 estimate of relevance/value to the research topic. */
38
+ relevance: number;
39
+ /** Human-readable justification (shown in the decision log + demo). */
40
+ rationale: string;
41
+ }
42
+ export type Action = "pay" | "skip" | "cache" | "approve";
43
+ /** The agent's verdict on one candidate, with a visible reason. */
44
+ export interface Decision {
45
+ slug: string;
46
+ title: string;
47
+ /** Canonical URL carried from the candidate (see `Candidate.url`) so the pay
48
+ * step targets the real link, not a reconstructed `/essays/<slug>` path. */
49
+ url?: string;
50
+ action: Action;
51
+ reason: string;
52
+ relevance: number;
53
+ price: number;
54
+ /** value density = relevance / price, the ranking key. */
55
+ density: number;
56
+ }
57
+ /** A source the agent actually obtained (paid or from cache) and can cite. */
58
+ export interface Source {
59
+ slug: string;
60
+ title: string;
61
+ content: string;
62
+ paidUsdc: number;
63
+ settlementRef?: string;
64
+ /** Citation License `jti` proving this read was paid for (verifiable at the gate). */
65
+ licenseId?: string;
66
+ }
67
+ export interface RunResult {
68
+ topic: string;
69
+ budget: number;
70
+ spent: number;
71
+ decisions: Decision[];
72
+ sources: Source[];
73
+ answer: string;
74
+ }
75
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE3C,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;mFACmF;AACnF,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,KAAK,EAAE,IAAI,CAAC;CACb;AAED,uEAAuE;AACvE,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACzD,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAE1D,mEAAmE;AACnE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd;iFAC6E;IAC7E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,8EAA8E;AAC9E,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ export interface AgentWallet {
2
+ address: string;
3
+ mock: boolean;
4
+ /**
5
+ * Sign an EIP-191 personal_sign message (a holder-of-key proof). Present
6
+ * whenever a private key is available (always, on the dev path). Absent only
7
+ * when BUYER_ADDRESS is set without a key — then PoP re-reads can't be proven.
8
+ */
9
+ signMessage?: (message: string) => Promise<string>;
10
+ }
11
+ export declare function getWallet(): AgentWallet;
12
+ //# sourceMappingURL=wallet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACpD;AAiBD,wBAAgB,SAAS,IAAI,WAAW,CAqBvC"}
package/dist/wallet.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The agent's wallet. With BUYER_PRIVATE_KEY set, derives the real Arc address
3
+ * via viem and can sign holder-of-key proofs. Without it, falls back to a
4
+ * deterministic DEV key (derived from a fixed non-secret seed, so it's stable
5
+ * across processes) so the full loop — including the proof-of-possession re-read
6
+ * across the two demo runs — works offline against the mock tollgate.
7
+ * BUYER_ADDRESS still overrides the address for legacy/no-sign demos, but then
8
+ * proofs won't match the dev key (re-read safely falls back to paying).
9
+ */
10
+ import { createHash } from "node:crypto";
11
+ import { privateKeyToAccount } from "viem/accounts";
12
+ import { getConfig } from "@naulon/shared";
13
+ /**
14
+ * A deterministic, non-secret DEV key derived from a fixed seed — never used with
15
+ * real funds. It gives the offline mock agent a consistent address+key (stable
16
+ * across the two demo runs) so it can sign PoP proofs without any real wallet.
17
+ * Derived at runtime so no key material is committed to the repo.
18
+ */
19
+ function devDemoKey() {
20
+ const bytes = createHash("sha256").update("naulon:dev-wallet:v1").digest();
21
+ return `0x${bytes.toString("hex")}`;
22
+ }
23
+ function normalizeKey(raw) {
24
+ return (raw.startsWith("0x") ? raw : `0x${raw}`);
25
+ }
26
+ export function getWallet() {
27
+ const cfg = getConfig();
28
+ if (cfg.BUYER_PRIVATE_KEY) {
29
+ const account = privateKeyToAccount(normalizeKey(cfg.BUYER_PRIVATE_KEY));
30
+ return {
31
+ address: account.address,
32
+ mock: false,
33
+ signMessage: (message) => account.signMessage({ message }),
34
+ };
35
+ }
36
+ // No real key: use the derived dev key so the agent has a consistent signable
37
+ // identity. A caller-supplied BUYER_ADDRESS still wins for the address (legacy
38
+ // demos), but the dev key signs — only matching when BUYER_ADDRESS is unset.
39
+ const account = privateKeyToAccount(devDemoKey());
40
+ return {
41
+ address: cfg.BUYER_ADDRESS ?? account.address,
42
+ mock: true,
43
+ signMessage: (message) => account.signMessage({ message }),
44
+ };
45
+ }
46
+ //# sourceMappingURL=wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAa3C;;;;;GAKG;AACH,SAAS,UAAU;IACjB,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,MAAM,EAAE,CAAC;IAC3E,OAAO,KAAK,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAkB,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IAExB,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,mBAAmB,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACzE,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,KAAK;YACX,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;SAC3D,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,+EAA+E;IAC/E,6EAA6E;IAC7E,MAAM,OAAO,GAAG,mBAAmB,CAAC,UAAU,EAAE,CAAC,CAAC;IAClD,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,OAAO;QAC7C,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@naulon/wayfarer",
3
+ "version": "0.1.1",
4
+ "description": "The naulon paying agent: discover → quote → appraise → decide → pay → ground. Budgeted x402 buying over Circle Gateway on Arc, with reusable Citation Licenses (pay once, re-read free).",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/naulonapp/naulon.git",
9
+ "directory": "packages/wayfarer"
10
+ },
11
+ "type": "module",
12
+ "main": "./dist/lib.js",
13
+ "types": "./dist/lib.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/lib.d.ts",
17
+ "import": "./dist/lib.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "dev": "tsx watch src/index.ts",
25
+ "start": "tsx src/index.ts",
26
+ "build": "tsc -p tsconfig.json",
27
+ "prepublishOnly": "npm run build",
28
+ "test": "node --import tsx --test \"src/**/*.test.ts\""
29
+ },
30
+ "dependencies": {
31
+ "@naulon/shared": "^0.1.2",
32
+ "@circle-fin/x402-batching": "^3.2.0",
33
+ "@langchain/core": "^1.1.48",
34
+ "@langchain/openai": "^1.4.7",
35
+ "@x402/core": "^2.6.0",
36
+ "@x402/evm": "^2.6.0",
37
+ "viem": "^2.52.2"
38
+ },
39
+ "engines": {
40
+ "node": ">=22"
41
+ }
42
+ }