@avow-finance/sdk 0.0.0-stage → 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.
Files changed (267) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +122 -2
  3. package/dist/agent-entry.d.ts +15 -0
  4. package/dist/agent-entry.d.ts.map +1 -0
  5. package/dist/agent-entry.js +11 -0
  6. package/dist/agent-entry.js.map +1 -0
  7. package/dist/agent-key.d.ts +34 -0
  8. package/dist/agent-key.d.ts.map +1 -0
  9. package/dist/agent-key.js +33 -0
  10. package/dist/agent-key.js.map +1 -0
  11. package/dist/agent.d.ts +261 -0
  12. package/dist/agent.d.ts.map +1 -0
  13. package/dist/agent.js +493 -0
  14. package/dist/agent.js.map +1 -0
  15. package/dist/avow-api.d.ts +78 -0
  16. package/dist/avow-api.d.ts.map +1 -0
  17. package/dist/avow-api.js +2 -0
  18. package/dist/avow-api.js.map +1 -0
  19. package/dist/contest.d.ts +135 -0
  20. package/dist/contest.d.ts.map +1 -0
  21. package/dist/contest.js +186 -0
  22. package/dist/contest.js.map +1 -0
  23. package/dist/http.d.ts +161 -0
  24. package/dist/http.d.ts.map +1 -0
  25. package/dist/http.js +311 -0
  26. package/dist/http.js.map +1 -0
  27. package/dist/index.d.ts +38 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +38 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/job/accept.d.ts +84 -0
  32. package/dist/job/accept.d.ts.map +1 -0
  33. package/dist/job/accept.js +136 -0
  34. package/dist/job/accept.js.map +1 -0
  35. package/dist/job/customer.d.ts +43 -0
  36. package/dist/job/customer.d.ts.map +1 -0
  37. package/dist/job/customer.js +83 -0
  38. package/dist/job/customer.js.map +1 -0
  39. package/dist/job/quote.d.ts +34 -0
  40. package/dist/job/quote.d.ts.map +1 -0
  41. package/dist/job/quote.js +37 -0
  42. package/dist/job/quote.js.map +1 -0
  43. package/dist/lock.d.ts +269 -0
  44. package/dist/lock.d.ts.map +1 -0
  45. package/dist/lock.js +283 -0
  46. package/dist/lock.js.map +1 -0
  47. package/dist/moderato.d.ts +27 -0
  48. package/dist/moderato.d.ts.map +1 -0
  49. package/dist/moderato.js +34 -0
  50. package/dist/moderato.js.map +1 -0
  51. package/dist/node/cli.d.ts +3 -0
  52. package/dist/node/cli.d.ts.map +1 -0
  53. package/dist/node/cli.js +346 -0
  54. package/dist/node/cli.js.map +1 -0
  55. package/dist/node/connect.d.ts +15 -0
  56. package/dist/node/connect.d.ts.map +1 -0
  57. package/dist/node/connect.js +91 -0
  58. package/dist/node/connect.js.map +1 -0
  59. package/dist/node/eval.d.ts +3 -0
  60. package/dist/node/eval.d.ts.map +1 -0
  61. package/dist/node/eval.js +67 -0
  62. package/dist/node/eval.js.map +1 -0
  63. package/dist/node/first-run.d.ts +50 -0
  64. package/dist/node/first-run.d.ts.map +1 -0
  65. package/dist/node/first-run.js +149 -0
  66. package/dist/node/first-run.js.map +1 -0
  67. package/dist/node/job.d.ts +50 -0
  68. package/dist/node/job.d.ts.map +1 -0
  69. package/dist/node/job.js +176 -0
  70. package/dist/node/job.js.map +1 -0
  71. package/dist/node/mailbox.d.ts +19 -0
  72. package/dist/node/mailbox.d.ts.map +1 -0
  73. package/dist/node/mailbox.js +81 -0
  74. package/dist/node/mailbox.js.map +1 -0
  75. package/dist/node/mcp.d.ts +74 -0
  76. package/dist/node/mcp.d.ts.map +1 -0
  77. package/dist/node/mcp.js +367 -0
  78. package/dist/node/mcp.js.map +1 -0
  79. package/dist/node/platform.d.ts +35 -0
  80. package/dist/node/platform.d.ts.map +1 -0
  81. package/dist/node/platform.js +102 -0
  82. package/dist/node/platform.js.map +1 -0
  83. package/dist/node/runner-session.d.ts +41 -0
  84. package/dist/node/runner-session.d.ts.map +1 -0
  85. package/dist/node/runner-session.js +100 -0
  86. package/dist/node/runner-session.js.map +1 -0
  87. package/dist/node/runner.d.ts +63 -0
  88. package/dist/node/runner.d.ts.map +1 -0
  89. package/dist/node/runner.js +341 -0
  90. package/dist/node/runner.js.map +1 -0
  91. package/dist/node/service-child.d.ts +2 -0
  92. package/dist/node/service-child.d.ts.map +1 -0
  93. package/dist/node/service-child.js +40 -0
  94. package/dist/node/service-child.js.map +1 -0
  95. package/dist/node/service-excerpt.d.ts +21 -0
  96. package/dist/node/service-excerpt.d.ts.map +1 -0
  97. package/dist/node/service-excerpt.js +32 -0
  98. package/dist/node/service-excerpt.js.map +1 -0
  99. package/dist/node/service-process.d.ts +12 -0
  100. package/dist/node/service-process.d.ts.map +1 -0
  101. package/dist/node/service-process.js +132 -0
  102. package/dist/node/service-process.js.map +1 -0
  103. package/dist/node/session-input.d.ts +12 -0
  104. package/dist/node/session-input.d.ts.map +1 -0
  105. package/dist/node/session-input.js +42 -0
  106. package/dist/node/session-input.js.map +1 -0
  107. package/dist/node/session-view.d.ts +20 -0
  108. package/dist/node/session-view.d.ts.map +1 -0
  109. package/dist/node/session-view.js +198 -0
  110. package/dist/node/session-view.js.map +1 -0
  111. package/dist/node-agent.d.ts +2 -0
  112. package/dist/node-agent.d.ts.map +1 -0
  113. package/dist/node-agent.js +6 -0
  114. package/dist/node-agent.js.map +1 -0
  115. package/dist/node.d.ts +2 -0
  116. package/dist/node.d.ts.map +1 -0
  117. package/dist/node.js +9 -0
  118. package/dist/node.js.map +1 -0
  119. package/dist/sandbox/agent.d.ts +187 -0
  120. package/dist/sandbox/agent.d.ts.map +1 -0
  121. package/dist/sandbox/agent.js +468 -0
  122. package/dist/sandbox/agent.js.map +1 -0
  123. package/dist/sandbox/business-store.d.ts +19 -0
  124. package/dist/sandbox/business-store.d.ts.map +1 -0
  125. package/dist/sandbox/business-store.js +19 -0
  126. package/dist/sandbox/business-store.js.map +1 -0
  127. package/dist/sandbox/business.d.ts +70 -0
  128. package/dist/sandbox/business.d.ts.map +1 -0
  129. package/dist/sandbox/business.js +115 -0
  130. package/dist/sandbox/business.js.map +1 -0
  131. package/dist/sandbox/connect.d.ts +64 -0
  132. package/dist/sandbox/connect.d.ts.map +1 -0
  133. package/dist/sandbox/connect.js +182 -0
  134. package/dist/sandbox/connect.js.map +1 -0
  135. package/dist/sandbox/deployment.d.ts +14 -0
  136. package/dist/sandbox/deployment.d.ts.map +1 -0
  137. package/dist/sandbox/deployment.js +38 -0
  138. package/dist/sandbox/deployment.js.map +1 -0
  139. package/dist/sandbox/keys.d.ts +45 -0
  140. package/dist/sandbox/keys.d.ts.map +1 -0
  141. package/dist/sandbox/keys.js +132 -0
  142. package/dist/sandbox/keys.js.map +1 -0
  143. package/dist/sandbox/mailbox.d.ts +90 -0
  144. package/dist/sandbox/mailbox.d.ts.map +1 -0
  145. package/dist/sandbox/mailbox.js +400 -0
  146. package/dist/sandbox/mailbox.js.map +1 -0
  147. package/dist/sandbox/mandate.d.ts +84 -0
  148. package/dist/sandbox/mandate.d.ts.map +1 -0
  149. package/dist/sandbox/mandate.js +107 -0
  150. package/dist/sandbox/mandate.js.map +1 -0
  151. package/dist/sandbox/namespace.d.ts +16 -0
  152. package/dist/sandbox/namespace.d.ts.map +1 -0
  153. package/dist/sandbox/namespace.js +16 -0
  154. package/dist/sandbox/namespace.js.map +1 -0
  155. package/dist/sandbox/session.d.ts +60 -0
  156. package/dist/sandbox/session.d.ts.map +1 -0
  157. package/dist/sandbox/session.js +94 -0
  158. package/dist/sandbox/session.js.map +1 -0
  159. package/dist/sandbox/setup.d.ts +136 -0
  160. package/dist/sandbox/setup.d.ts.map +1 -0
  161. package/dist/sandbox/setup.js +490 -0
  162. package/dist/sandbox/setup.js.map +1 -0
  163. package/dist/sandbox/store.d.ts +69 -0
  164. package/dist/sandbox/store.d.ts.map +1 -0
  165. package/dist/sandbox/store.js +115 -0
  166. package/dist/sandbox/store.js.map +1 -0
  167. package/dist/sandbox/supplier-key.d.ts +73 -0
  168. package/dist/sandbox/supplier-key.d.ts.map +1 -0
  169. package/dist/sandbox/supplier-key.js +180 -0
  170. package/dist/sandbox/supplier-key.js.map +1 -0
  171. package/dist/sandbox/suppliers.d.ts +7 -0
  172. package/dist/sandbox/suppliers.d.ts.map +1 -0
  173. package/dist/sandbox/suppliers.js +29 -0
  174. package/dist/sandbox/suppliers.js.map +1 -0
  175. package/dist/sandbox/terms.d.ts +32 -0
  176. package/dist/sandbox/terms.d.ts.map +1 -0
  177. package/dist/sandbox/terms.js +58 -0
  178. package/dist/sandbox/terms.js.map +1 -0
  179. package/dist/sandbox/vault.d.ts +24 -0
  180. package/dist/sandbox/vault.d.ts.map +1 -0
  181. package/dist/sandbox/vault.js +54 -0
  182. package/dist/sandbox/vault.js.map +1 -0
  183. package/dist/send.d.ts +122 -0
  184. package/dist/send.d.ts.map +1 -0
  185. package/dist/send.js +328 -0
  186. package/dist/send.js.map +1 -0
  187. package/dist/service-entry.d.ts +6 -0
  188. package/dist/service-entry.d.ts.map +1 -0
  189. package/dist/service-entry.js +6 -0
  190. package/dist/service-entry.js.map +1 -0
  191. package/dist/session/anthropic.d.ts +17 -0
  192. package/dist/session/anthropic.d.ts.map +1 -0
  193. package/dist/session/anthropic.js +215 -0
  194. package/dist/session/anthropic.js.map +1 -0
  195. package/dist/session/charge.d.ts +13 -0
  196. package/dist/session/charge.d.ts.map +1 -0
  197. package/dist/session/charge.js +33 -0
  198. package/dist/session/charge.js.map +1 -0
  199. package/dist/session/data.d.ts +8 -0
  200. package/dist/session/data.d.ts.map +1 -0
  201. package/dist/session/data.js +20 -0
  202. package/dist/session/data.js.map +1 -0
  203. package/dist/session/eval.d.ts +41 -0
  204. package/dist/session/eval.d.ts.map +1 -0
  205. package/dist/session/eval.js +281 -0
  206. package/dist/session/eval.js.map +1 -0
  207. package/dist/session/executor.d.ts +80 -0
  208. package/dist/session/executor.d.ts.map +1 -0
  209. package/dist/session/executor.js +381 -0
  210. package/dist/session/executor.js.map +1 -0
  211. package/dist/session/fixture-world.d.ts +29 -0
  212. package/dist/session/fixture-world.d.ts.map +1 -0
  213. package/dist/session/fixture-world.js +708 -0
  214. package/dist/session/fixture-world.js.map +1 -0
  215. package/dist/session/live-world.d.ts +22 -0
  216. package/dist/session/live-world.d.ts.map +1 -0
  217. package/dist/session/live-world.js +329 -0
  218. package/dist/session/live-world.js.map +1 -0
  219. package/dist/session/ollama.d.ts +29 -0
  220. package/dist/session/ollama.d.ts.map +1 -0
  221. package/dist/session/ollama.js +177 -0
  222. package/dist/session/ollama.js.map +1 -0
  223. package/dist/session/provider.d.ts +79 -0
  224. package/dist/session/provider.d.ts.map +1 -0
  225. package/dist/session/provider.js +19 -0
  226. package/dist/session/provider.js.map +1 -0
  227. package/dist/session/scripted.d.ts +45 -0
  228. package/dist/session/scripted.d.ts.map +1 -0
  229. package/dist/session/scripted.js +236 -0
  230. package/dist/session/scripted.js.map +1 -0
  231. package/dist/session/selection.d.ts +37 -0
  232. package/dist/session/selection.d.ts.map +1 -0
  233. package/dist/session/selection.js +104 -0
  234. package/dist/session/selection.js.map +1 -0
  235. package/dist/session/service-check.d.ts +48 -0
  236. package/dist/session/service-check.d.ts.map +1 -0
  237. package/dist/session/service-check.js +86 -0
  238. package/dist/session/service-check.js.map +1 -0
  239. package/dist/session/service.d.ts +128 -0
  240. package/dist/session/service.d.ts.map +1 -0
  241. package/dist/session/service.js +150 -0
  242. package/dist/session/service.js.map +1 -0
  243. package/dist/session/session.d.ts +95 -0
  244. package/dist/session/session.d.ts.map +1 -0
  245. package/dist/session/session.js +312 -0
  246. package/dist/session/session.js.map +1 -0
  247. package/dist/session/toolbox.d.ts +69 -0
  248. package/dist/session/toolbox.d.ts.map +1 -0
  249. package/dist/session/toolbox.js +391 -0
  250. package/dist/session/toolbox.js.map +1 -0
  251. package/dist/session/tools.d.ts +45 -0
  252. package/dist/session/tools.d.ts.map +1 -0
  253. package/dist/session/tools.js +137 -0
  254. package/dist/session/tools.js.map +1 -0
  255. package/dist/session/world.d.ts +188 -0
  256. package/dist/session/world.d.ts.map +1 -0
  257. package/dist/session/world.js +2 -0
  258. package/dist/session/world.js.map +1 -0
  259. package/dist/sign.d.ts +19 -0
  260. package/dist/sign.d.ts.map +1 -0
  261. package/dist/sign.js +33 -0
  262. package/dist/sign.js.map +1 -0
  263. package/dist/supplier.d.ts +41 -0
  264. package/dist/supplier.d.ts.map +1 -0
  265. package/dist/supplier.js +57 -0
  266. package/dist/supplier.js.map +1 -0
  267. package/package.json +56 -3
@@ -0,0 +1,115 @@
1
+ import { mandateJson, parseReference, parseSigned, toWire, } from '@avow-finance/spec';
2
+ import { isAddress } from 'viem';
3
+ /** A store held in memory, for a test or a page that shouldn't keep anything. */
4
+ export function memoryStore() {
5
+ const items = new Map();
6
+ return {
7
+ read: async (item) => items.get(item) ?? null,
8
+ write: async (item, text) => {
9
+ items.set(item, text);
10
+ },
11
+ };
12
+ }
13
+ const isKey = (v) => typeof v === 'string' && /^0x[0-9a-f]{64}$/i.test(v);
14
+ export const isAddressText = (v) => typeof v === 'string' && isAddress(v);
15
+ export const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
16
+ export function readJson(text, item) {
17
+ try {
18
+ const json = JSON.parse(text);
19
+ if (isRecord(json))
20
+ return json;
21
+ }
22
+ catch {
23
+ // Reported below, without the text.
24
+ }
25
+ throw new Error(`The sandbox's ${item} file isn't readable. Move the .avow folder aside to start over.`);
26
+ }
27
+ export const write = (store, item, value) => store.write(item, `${JSON.stringify(toWire({ version: 1, ...value }), null, 2)}\n`);
28
+ export function readBusiness(json) {
29
+ if (!isRecord(json))
30
+ return null;
31
+ const ok = typeof json.chainId === 'number' &&
32
+ typeof json.apiUrl === 'string' &&
33
+ typeof json.businessId === 'string' &&
34
+ isAddressText(json.factory) &&
35
+ isAddressText(json.token) &&
36
+ isAddressText(json.account) &&
37
+ isAddressText(json.lock);
38
+ return ok ? json : null;
39
+ }
40
+ function readSuppliers(json) {
41
+ if (!Array.isArray(json))
42
+ return null;
43
+ const suppliers = json.filter((s) => isRecord(s) && typeof s.id === 'string' && typeof s.url === 'string');
44
+ return suppliers.length === json.length ? suppliers.map((s) => ({ id: s.id, url: s.url })) : null;
45
+ }
46
+ /** The agent's item, or null when the business hasn't enrolled an agent. */
47
+ export async function loadAgentItem(store) {
48
+ const text = await store.read('agent');
49
+ if (text === null)
50
+ return null;
51
+ const json = readJson(text, 'agent');
52
+ const business = readBusiness(json.business);
53
+ const suppliers = readSuppliers(json.suppliers);
54
+ if (!business ||
55
+ !suppliers ||
56
+ !isKey(json.agentKey) ||
57
+ !isKey(json.mandateHash) ||
58
+ !isKey(json.keyAuthorizedIn)) {
59
+ return null;
60
+ }
61
+ const mandate = parseSigned(json.mandate, 'Mandate', mandateJson, {
62
+ chainId: business.chainId,
63
+ lock: business.lock,
64
+ });
65
+ if (!mandate.ok)
66
+ return null;
67
+ return {
68
+ agentKey: json.agentKey,
69
+ business,
70
+ mandate: mandate.value,
71
+ mandateHash: json.mandateHash,
72
+ keyAuthorizedIn: json.keyAuthorizedIn,
73
+ suppliers,
74
+ };
75
+ }
76
+ export const saveAgentItem = (store, item) => write(store, 'agent', item);
77
+ /** The commitments the agent made, as far as each still parses. */
78
+ export async function loadCommitments(store) {
79
+ const text = await store.read('state');
80
+ if (text === null)
81
+ return [];
82
+ const json = readJson(text, 'state');
83
+ if (!Array.isArray(json.commitments))
84
+ return [];
85
+ return json.commitments.flatMap((c) => {
86
+ if (!isRecord(c))
87
+ return [];
88
+ const reference = parseReference(c.reference);
89
+ if (!reference.ok ||
90
+ reference.value.kind !== 'commitment' ||
91
+ typeof c.amount !== 'string' ||
92
+ !/^[0-9]+$/.test(c.amount) ||
93
+ typeof c.supplier !== 'string' ||
94
+ !isKey(c.mandateHash) ||
95
+ typeof c.madeAt !== 'string' ||
96
+ !/^[0-9]+$/.test(c.madeAt)) {
97
+ return [];
98
+ }
99
+ return [
100
+ {
101
+ reference: reference.value,
102
+ amount: BigInt(c.amount),
103
+ supplier: c.supplier,
104
+ mandateHash: c.mandateHash,
105
+ madeAt: BigInt(c.madeAt),
106
+ },
107
+ ];
108
+ });
109
+ }
110
+ export const saveCommitments = (store, commitments) => write(store, 'state', { commitments });
111
+ /** Adds one commitment, reading the list again first so another process's addition isn't lost. */
112
+ export async function addCommitment(store, c) {
113
+ await saveCommitments(store, [...(await loadCommitments(store)), c]);
114
+ }
115
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/sandbox/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,EACX,cAAc,EACd,WAAW,EAEX,MAAM,GACP,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAA0B,SAAS,EAAE,MAAM,MAAM,CAAA;AAqBxD,iFAAiF;AACjF,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAA;IACjD,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QAC7C,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YAC1B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACvB,CAAC;KACF,CAAA;AACH,CAAC;AAwCD,MAAM,KAAK,GAAG,CAAC,CAAU,EAAY,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAU,EAAgB,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,CAAA;AAChG,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAgC,EAAE,CACnE,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AAE1D,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAsB;IAC3D,IAAI,CAAC;QACH,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACtC,IAAI,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IACD,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,kEAAkE,CACxF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAmB,EAAE,IAAsB,EAAE,KAAa,EAAE,EAAE,CAClF,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;AAErF,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAChC,MAAM,EAAE,GACN,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;QAChC,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;QAC/B,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ;QACnC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;QAC3B,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QACzB,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;QAC3B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC1B,OAAO,EAAE,CAAC,CAAC,CAAE,IAAkC,CAAC,CAAC,CAAC,IAAI,CAAA;AACxD,CAAC;AAED,SAAS,aAAa,CAAC,IAAa;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAC3B,CAAC,CAAC,EAAwB,EAAE,CAC1B,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CACvE,CAAA;IACD,OAAO,SAAS,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACnG,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAmB;IACrD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC5C,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC/C,IACE,CAAC,QAAQ;QACT,CAAC,SAAS;QACV,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;QACrB,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;QACxB,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,EAC5B,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE;QAChE,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;KACpB,CAAC,CAAA;IACF,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,IAAI,CAAA;IAC5B,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ;QACR,OAAO,EAAE,OAAO,CAAC,KAAwB;QACzC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,SAAS;KACV,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAmB,EAAE,IAAe,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;AAElG,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAmB;IACvD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,CAAA;IAC5B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAA;IAC/C,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAU,EAAsB,EAAE;QACjE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,CAAA;QAC3B,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC7C,IACE,CAAC,SAAS,CAAC,EAAE;YACb,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY;YACrC,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;YAC5B,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;YAC1B,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;YAC9B,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC;YACrB,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;YAC5B,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAC1B,CAAC;YACD,OAAO,EAAE,CAAA;QACX,CAAC;QACD,OAAO;YACL;gBACE,SAAS,EAAE,SAAS,CAAC,KAAK;gBAC1B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;gBACxB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;aACzB;SACF,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAmB,EAAE,WAAwC,EAAE,EAAE,CAC/F,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,CAAC,CAAA;AAExC,kGAAkG;AAClG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAmB,EAAE,CAAmB;IAC1E,MAAM,eAAe,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AACtE,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { type SandboxDeployment, type SupplierProfile } from '@avow-finance/spec';
2
+ import { type Address, type Hex } from 'viem';
3
+ import { type PrivateKeyAccount } from 'viem/accounts';
4
+ import type { Account as TempoAccount } from 'viem/tempo';
5
+ import { type SandboxClient } from './business.js';
6
+ import { type SandboxStore, type StoredBusiness } from './store.js';
7
+ /**
8
+ * The business as a supplier of jobs. Its signing key is made on this machine and kept beside the
9
+ * agent's key, outside the passphrase, since the job process signs with it: the business's quotes,
10
+ * its acceptances of a customer's reserve and its requests to the test customer. It can't move the
11
+ * business's money or change its authority, which only the root key does.
12
+ */
13
+ export interface SupplierItem {
14
+ signingKey: Hex;
15
+ /** The supplier as Avow registered it, under the business's account. */
16
+ profile: SupplierProfile;
17
+ /** The business it was registered for, on the deployment it was registered on. */
18
+ business: StoredBusiness;
19
+ }
20
+ /** The supplier's item, or null when the business has no signing key yet or the file doesn't read. */
21
+ export declare function loadSupplierItem(store: SandboxStore): Promise<SupplierItem | null>;
22
+ /**
23
+ * Registers the business with Avow's sandbox as a supplier, under its own account, with the given
24
+ * signing key and its account as the payout address. The root key and the signing key both sign
25
+ * the registration, and the root key signs the request around it, naming the factory. Avow answers
26
+ * a repeat of the same three addresses with the supplier it holds, and the answer has to name them.
27
+ */
28
+ export declare function registerSandboxSupplier(deps: {
29
+ deployment: Pick<SandboxDeployment, 'chainId' | 'apiUrl' | 'factory'>;
30
+ root: TempoAccount.RootAccount;
31
+ signingKey: PrivateKeyAccount;
32
+ payee: Address;
33
+ now?: () => bigint;
34
+ fetch?: typeof fetch;
35
+ }): Promise<SupplierProfile>;
36
+ /**
37
+ * Completes a supplier registration the business's administrator started in the console. The
38
+ * console signs the registration of this agent's signing key with the account's root key, and the
39
+ * agent signs it with the signing key, proving it holds the key, and sends it to Avow signed with
40
+ * that key. The supplier item it keeps is the one quoting and accepting jobs read. The signing key
41
+ * pays its own fees, so Moderato's faucet funds them first.
42
+ */
43
+ export declare function completeSupplierRegistration(m: {
44
+ store: SandboxStore;
45
+ deployment: Pick<SandboxDeployment, 'chainId' | 'apiUrl' | 'factory'>;
46
+ business: StoredBusiness;
47
+ client: SandboxClient;
48
+ signingKey: Hex;
49
+ /** The registration and the account's signature on it, as the approval carried them. */
50
+ partial: {
51
+ registration: Record<string, unknown>;
52
+ accountSignature: Hex;
53
+ };
54
+ fetch?: typeof fetch;
55
+ }): Promise<SupplierItem>;
56
+ /**
57
+ * The business's supplier item, registering the business as a supplier first when this folder has
58
+ * none for it. A key already made for the same account is registered again, since Avow answers a
59
+ * repeat with the supplier it holds, and anything else gets a new key. Registering takes the root
60
+ * key, which `openRoot` opens. The signing key sends the business's acceptances itself, so whenever
61
+ * it holds too little for its fees Moderato's faucet funds them, which costs one balance read once
62
+ * it's funded. A registration Avow refuses says plainly why.
63
+ */
64
+ export declare function ensureSandboxSupplier(m: {
65
+ store: SandboxStore;
66
+ business: StoredBusiness;
67
+ deployment: Pick<SandboxDeployment, 'chainId' | 'apiUrl' | 'factory'>;
68
+ client: SandboxClient;
69
+ openRoot: () => Promise<TempoAccount.RootAccount>;
70
+ log: (line: string, kind?: 'wait' | 'done' | 'detail') => void;
71
+ fetch?: typeof fetch;
72
+ }): Promise<SupplierItem>;
73
+ //# sourceMappingURL=supplier-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supplier-key.d.ts","sourceRoot":"","sources":["../../src/sandbox/supplier-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,iBAAiB,EACtB,KAAK,eAAe,EAGrB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,GAAG,EAAkB,MAAM,MAAM,CAAA;AAC7D,OAAO,EAAsB,KAAK,iBAAiB,EAAuB,MAAM,eAAe,CAAA;AAC/F,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzD,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC5D,OAAO,EAA0B,KAAK,YAAY,EAAE,KAAK,cAAc,EAAS,MAAM,YAAY,CAAA;AAElG;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,GAAG,CAAA;IACf,wEAAwE;IACxE,OAAO,EAAE,eAAe,CAAA;IACxB,kFAAkF;IAClF,QAAQ,EAAE,cAAc,CAAA;CACzB;AAOD,sGAAsG;AACtG,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAaxF;AAYD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAA;IACrE,IAAI,EAAE,YAAY,CAAC,WAAW,CAAA;IAC9B,UAAU,EAAE,iBAAiB,CAAA;IAC7B,KAAK,EAAE,OAAO,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwC3B;AAED;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EAAE;IACpD,KAAK,EAAE,YAAY,CAAA;IACnB,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAA;IACrE,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,aAAa,CAAA;IACrB,UAAU,EAAE,GAAG,CAAA;IACf,wFAAwF;IACxF,OAAO,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,gBAAgB,EAAE,GAAG,CAAA;KAAE,CAAA;IACzE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB,GAAG,OAAO,CAAC,YAAY,CAAC,CAiDxB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE;IAC7C,KAAK,EAAE,YAAY,CAAA;IACnB,QAAQ,EAAE,cAAc,CAAA;IACxB,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAA;IACrE,MAAM,EAAE,aAAa,CAAA;IACrB,QAAQ,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;IACjD,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAA;IAC9D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB,GAAG,OAAO,CAAC,YAAY,CAAC,CAyCxB"}
@@ -0,0 +1,180 @@
1
+ import { parseSupplierProfile, registrationDigest, registrationDomain, SANDBOX_PATHS, signSupplierRegistration, supplierRegistrationBody, } from '@avow-finance/spec';
2
+ import { isAddressEqual } from 'viem';
3
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
4
+ import { AvowApiError, avowRequests, rootRequestKey, signingRequestKey } from '../http.js';
5
+ import { fundFees } from './business.js';
6
+ import { readBusiness, readJson, write } from './store.js';
7
+ /** How long a registration the two keys sign stays valid, well inside the API's five minutes. */
8
+ const REGISTRATION_VALIDITY = 120n;
9
+ const systemClock = () => BigInt(Math.floor(Date.now() / 1000));
10
+ const isKey = (v) => typeof v === 'string' && /^0x[0-9a-f]{64}$/i.test(v);
11
+ /** The supplier's item, or null when the business has no signing key yet or the file doesn't read. */
12
+ export async function loadSupplierItem(store) {
13
+ const text = await store.read('supplier');
14
+ if (text === null)
15
+ return null;
16
+ const json = readJson(text, 'supplier');
17
+ const business = readBusiness(json.business);
18
+ const profile = parseSupplierProfile(json.profile);
19
+ if (!business || !profile.ok || !isKey(json.signingKey))
20
+ return null;
21
+ // The file names the key's address too, so a key that isn't the registered one never signs.
22
+ const signingKey = json.signingKey;
23
+ if (!isAddressEqual(privateKeyToAccount(signingKey).address, profile.value.signingKey)) {
24
+ return null;
25
+ }
26
+ return { signingKey, profile: profile.value, business };
27
+ }
28
+ const saveSupplierItem = (store, item) => write(store, 'supplier', item);
29
+ /** Whether a supplier item was made for this business, on the deployment it runs on now. */
30
+ const madeFor = (item, business) => item.business.chainId === business.chainId &&
31
+ item.business.apiUrl === business.apiUrl &&
32
+ isAddressEqual(item.business.account, business.account) &&
33
+ item.business.businessId === business.businessId &&
34
+ isAddressEqual(item.profile.account, business.account);
35
+ /**
36
+ * Registers the business with Avow's sandbox as a supplier, under its own account, with the given
37
+ * signing key and its account as the payout address. The root key and the signing key both sign
38
+ * the registration, and the root key signs the request around it, naming the factory. Avow answers
39
+ * a repeat of the same three addresses with the supplier it holds, and the answer has to name them.
40
+ */
41
+ export async function registerSandboxSupplier(deps) {
42
+ const { deployment, root, signingKey, payee } = deps;
43
+ const body = await signSupplierRegistration({
44
+ chainId: deployment.chainId,
45
+ factory: deployment.factory,
46
+ audience: deployment.apiUrl,
47
+ account: root.address,
48
+ payee,
49
+ rootKey: root,
50
+ signingKey,
51
+ now: (deps.now ?? systemClock)(),
52
+ validity: REGISTRATION_VALIDITY,
53
+ });
54
+ const read = (json) => {
55
+ const profile = parseSupplierProfile(json);
56
+ if (!profile.ok)
57
+ return profile;
58
+ const p = profile.value;
59
+ const named = isAddressEqual(p.account, root.address) &&
60
+ isAddressEqual(p.payee, payee) &&
61
+ isAddressEqual(p.signingKey, signingKey.address);
62
+ return named ? profile : { ok: false, reason: 'message.invalid' };
63
+ };
64
+ return avowRequests({
65
+ baseUrl: deployment.apiUrl,
66
+ key: rootRequestKey(root),
67
+ retryFor: 120n,
68
+ ...(deps.fetch ? { fetch: deps.fetch } : {}),
69
+ })({
70
+ domain: { chainId: deployment.chainId, verifyingContract: deployment.factory },
71
+ path: SANDBOX_PATHS.suppliers,
72
+ body,
73
+ read,
74
+ }).catch((error) => {
75
+ if (!(error instanceof AvowApiError))
76
+ throw error;
77
+ throw new Error(`Avow's sandbox didn't register your business as a supplier (${error.reason ?? 'no answer'}): ${error.message}`, { cause: error });
78
+ });
79
+ }
80
+ /**
81
+ * Completes a supplier registration the business's administrator started in the console. The
82
+ * console signs the registration of this agent's signing key with the account's root key, and the
83
+ * agent signs it with the signing key, proving it holds the key, and sends it to Avow signed with
84
+ * that key. The supplier item it keeps is the one quoting and accepting jobs read. The signing key
85
+ * pays its own fees, so Moderato's faucet funds them first.
86
+ */
87
+ export async function completeSupplierRegistration(m) {
88
+ const signer = privateKeyToAccount(m.signingKey);
89
+ const parsed = supplierRegistrationBody.safeParse({
90
+ registration: m.partial.registration,
91
+ accountSignature: m.partial.accountSignature,
92
+ signingKeySignature: '0x00',
93
+ });
94
+ if (!parsed.success)
95
+ throw new Error("The supplier registration in the approval doesn't read");
96
+ const r = parsed.data.registration;
97
+ if (!isAddressEqual(r.signingKey, signer.address) ||
98
+ !isAddressEqual(r.account, m.business.account)) {
99
+ throw new Error("The supplier registration names another key or business, so this agent won't sign it.");
100
+ }
101
+ const hash = registrationDigest(registrationDomain(m.deployment.chainId, m.deployment.factory), {
102
+ kind: 'supplier',
103
+ registration: r,
104
+ });
105
+ const body = {
106
+ registration: r,
107
+ accountSignature: m.partial.accountSignature,
108
+ signingKeySignature: await signer.sign({ hash }),
109
+ };
110
+ const profile = await avowRequests({
111
+ baseUrl: m.deployment.apiUrl,
112
+ key: signingRequestKey(signer),
113
+ retryFor: 60n,
114
+ ...(m.fetch ? { fetch: m.fetch } : {}),
115
+ })({
116
+ domain: { chainId: m.deployment.chainId, verifyingContract: m.deployment.factory },
117
+ path: SANDBOX_PATHS.suppliers,
118
+ body,
119
+ read: (json) => {
120
+ const read = parseSupplierProfile(json);
121
+ if (!read.ok)
122
+ return read;
123
+ const p = read.value;
124
+ return isAddressEqual(p.account, m.business.account) &&
125
+ isAddressEqual(p.signingKey, signer.address)
126
+ ? read
127
+ : { ok: false, reason: 'message.invalid' };
128
+ },
129
+ });
130
+ const item = { signingKey: m.signingKey, profile, business: m.business };
131
+ await saveSupplierItem(m.store, item);
132
+ await fundFees(m.client, signer.address);
133
+ return item;
134
+ }
135
+ /**
136
+ * The business's supplier item, registering the business as a supplier first when this folder has
137
+ * none for it. A key already made for the same account is registered again, since Avow answers a
138
+ * repeat with the supplier it holds, and anything else gets a new key. Registering takes the root
139
+ * key, which `openRoot` opens. The signing key sends the business's acceptances itself, so whenever
140
+ * it holds too little for its fees Moderato's faucet funds them, which costs one balance read once
141
+ * it's funded. A registration Avow refuses says plainly why.
142
+ */
143
+ export async function ensureSandboxSupplier(m) {
144
+ const held = await loadSupplierItem(m.store);
145
+ if (held && madeFor(held, m.business)) {
146
+ await fundFees(m.client, held.profile.signingKey);
147
+ return held;
148
+ }
149
+ m.log('Giving your business a signing key to quote jobs', 'wait');
150
+ m.log("Your business's signing key is made on this machine and stays here. It quotes and accepts jobs and reports charges for your business, and it can't move your business's own money or change its authority.", 'detail');
151
+ const sameAccount = held !== null && isAddressEqual(held.business.account, m.business.account);
152
+ const signingKey = sameAccount ? held.signingKey : generatePrivateKey();
153
+ let profile;
154
+ try {
155
+ profile = await registerSandboxSupplier({
156
+ deployment: m.deployment,
157
+ root: await m.openRoot(),
158
+ signingKey: privateKeyToAccount(signingKey),
159
+ payee: m.business.account,
160
+ ...(m.fetch ? { fetch: m.fetch } : {}),
161
+ });
162
+ }
163
+ catch (error) {
164
+ const taken = error instanceof Error &&
165
+ error.cause instanceof AvowApiError &&
166
+ error.cause.reason === 'sandbox.taken';
167
+ if (!taken)
168
+ throw error;
169
+ throw new Error("Avow already holds another signing key for your business as a supplier, and .avow/supplier.json doesn't hold that key, so your business can't take jobs. Put back the supplier.json that holds it, or set up a fresh business with npm run fresh, which registers a key of its own.", { cause: error });
170
+ }
171
+ const item = { signingKey, profile, business: m.business };
172
+ await saveSupplierItem(m.store, item);
173
+ m.log('Your business can quote jobs, with a signing key of its own', 'done');
174
+ m.log(`Its signing key is ${profile.signingKey}.`, 'detail');
175
+ // The signing key sends the business's acceptances and pays their fees itself, so Moderato's
176
+ // faucet funds its fees as it funds the account's, and tops them up whenever they run low.
177
+ await fundFees(m.client, profile.signingKey);
178
+ return item;
179
+ }
180
+ //# sourceMappingURL=supplier-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supplier-key.js","sourceRoot":"","sources":["../../src/sandbox/supplier-key.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type SupplierConnection } from '../supplier.js';
2
+ import type { SandboxSupplier } from './store.js';
3
+ /** The suppliers a business names, checked: at least one, each id once, each an http(s) URL. */
4
+ export declare function checkSuppliers(suppliers: readonly SandboxSupplier[]): SandboxSupplier[];
5
+ /** Connects to a supplier's adapter and checks its profile names the supplier expected. */
6
+ export declare function connectSupplier(s: SandboxSupplier, send: typeof fetch): Promise<SupplierConnection>;
7
+ //# sourceMappingURL=suppliers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppliers.d.ts","sourceRoot":"","sources":["../../src/sandbox/suppliers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,gGAAgG;AAChG,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,GAAG,eAAe,EAAE,CAevF;AAED,2FAA2F;AAC3F,wBAAsB,eAAe,CACnC,CAAC,EAAE,eAAe,EAClB,IAAI,EAAE,OAAO,KAAK,GACjB,OAAO,CAAC,kBAAkB,CAAC,CAQ7B"}
@@ -0,0 +1,29 @@
1
+ import { httpSupplier } from '../supplier.js';
2
+ /** The suppliers a business names, checked: at least one, each id once, each an http(s) URL. */
3
+ export function checkSuppliers(suppliers) {
4
+ if (suppliers.length === 0)
5
+ throw new RangeError('The agent needs at least one supplier');
6
+ const ids = new Set();
7
+ for (const s of suppliers) {
8
+ if (typeof s.id !== 'string' || !/^[A-Za-z0-9_.-]{1,100}$/.test(s.id)) {
9
+ throw new RangeError(`${String(s.id)} isn't a supplier's business id`);
10
+ }
11
+ if (ids.has(s.id))
12
+ throw new RangeError(`${s.id} is listed twice`);
13
+ ids.add(s.id);
14
+ const url = new URL(s.url);
15
+ if (url.protocol !== 'https:' && url.protocol !== 'http:') {
16
+ throw new RangeError(`${s.url} isn't an http or https URL`);
17
+ }
18
+ }
19
+ return suppliers.map((s) => ({ id: s.id, url: s.url }));
20
+ }
21
+ /** Connects to a supplier's adapter and checks its profile names the supplier expected. */
22
+ export async function connectSupplier(s, send) {
23
+ const connection = await httpSupplier(s.url, send);
24
+ if (connection.profile.businessId !== s.id) {
25
+ throw new Error(`The supplier at ${s.url} says it's ${connection.profile.businessId}, not ${s.id}, so the agent won't commit to it.`);
26
+ }
27
+ return connection;
28
+ }
29
+ //# sourceMappingURL=suppliers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppliers.js","sourceRoot":"","sources":["../../src/sandbox/suppliers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA2B,MAAM,gBAAgB,CAAA;AAGtE,gGAAgG;AAChG,MAAM,UAAU,cAAc,CAAC,SAAqC;IAClE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,uCAAuC,CAAC,CAAA;IACzF,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAA;IAC7B,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,iCAAiC,CAAC,CAAA;QACxE,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAA;QAClE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACb,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC1B,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAC1D,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,6BAA6B,CAAC,CAAA;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;AACzD,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,CAAkB,EAClB,IAAkB;IAElB,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAClD,IAAI,UAAU,CAAC,OAAO,CAAC,UAAU,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,mBAAmB,CAAC,CAAC,GAAG,cAAc,UAAU,CAAC,OAAO,CAAC,UAAU,SAAS,CAAC,CAAC,EAAE,oCAAoC,CACrH,CAAA;IACH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { type GpuReservationTerms, type SandboxDeployment } from '@avow-finance/spec';
2
+ /**
3
+ * How long after booking the window opens. It leaves the supplier time to check the commitment and
4
+ * accept before the window, and free cancellation ends halfway there.
5
+ */
6
+ export declare const SANDBOX_STARTS_IN: bigint;
7
+ /** What a sandbox booking asks for: so many GPUs of one kind, for so many hours. */
8
+ export interface SandboxResource {
9
+ gpu: string;
10
+ count: number;
11
+ hours: number;
12
+ }
13
+ /** Dollars, whole or with cents, in micros. */
14
+ export declare function micros(amount: number, what: string): bigint;
15
+ /** Micros as dollars, the unit a sandbox booking is written in. */
16
+ export declare const toDollars: (amount: bigint) => number;
17
+ /**
18
+ * A sandbox booking's GPU reservation terms, as the buyer quickstart books them. The window opens
19
+ * four minutes after `now` and lasts the resource's hours. Free cancellation ends two minutes in, a
20
+ * late cancellation costs half the reserve, a no-show costs the whole reserve after two minutes'
21
+ * grace, and the reserve goes back at the window's end when nothing is reported. Usage is $3 per
22
+ * GPU-hour, paid apart from the reserve.
23
+ */
24
+ export declare function sandboxTerms(b: {
25
+ deployment: Pick<SandboxDeployment, 'arbiter' | 'day90SupplierShareBps'>;
26
+ resource: SandboxResource;
27
+ /** In micros. */
28
+ reserve: bigint;
29
+ /** Unix seconds. */
30
+ now: bigint;
31
+ }): GpuReservationTerms;
32
+ //# sourceMappingURL=terms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terms.d.ts","sourceRoot":"","sources":["../../src/sandbox/terms.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EAExB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAA;AAI3B;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAAc,CAAA;AAE5C,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,+CAA+C;AAC/C,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED,mEAAmE;AACnE,eAAO,MAAM,SAAS,WAAY,MAAM,KAAG,MAAoC,CAAA;AAE/E;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE;IAC9B,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,uBAAuB,CAAC,CAAA;IACxE,QAAQ,EAAE,eAAe,CAAA;IACzB,iBAAiB;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,mBAAmB,CAgCtB"}
@@ -0,0 +1,58 @@
1
+ import { dollars, gpuReservationTerms, } from '@avow-finance/spec';
2
+ const MINUTE = 60n;
3
+ /**
4
+ * How long after booking the window opens. It leaves the supplier time to check the commitment and
5
+ * accept before the window, and free cancellation ends halfway there.
6
+ */
7
+ export const SANDBOX_STARTS_IN = 4n * MINUTE;
8
+ /** Dollars, whole or with cents, in micros. */
9
+ export function micros(amount, what) {
10
+ const cents = Math.round(amount * 100);
11
+ if (!Number.isFinite(amount) || amount <= 0 || Math.abs(amount * 100 - cents) > 1e-6) {
12
+ throw new RangeError(`The ${what} has to be a positive amount of dollars, such as 200 or 12.50`);
13
+ }
14
+ return BigInt(cents) * 10000n;
15
+ }
16
+ /** Micros as dollars, the unit a sandbox booking is written in. */
17
+ export const toDollars = (amount) => Number(amount) / 1_000_000;
18
+ /**
19
+ * A sandbox booking's GPU reservation terms, as the buyer quickstart books them. The window opens
20
+ * four minutes after `now` and lasts the resource's hours. Free cancellation ends two minutes in, a
21
+ * late cancellation costs half the reserve, a no-show costs the whole reserve after two minutes'
22
+ * grace, and the reserve goes back at the window's end when nothing is reported. Usage is $3 per
23
+ * GPU-hour, paid apart from the reserve.
24
+ */
25
+ export function sandboxTerms(b) {
26
+ const { gpu, count, hours } = b.resource;
27
+ if (!/^[A-Za-z0-9-]{1,32}$/.test(gpu)) {
28
+ throw new RangeError('The GPU has to be a model name such as H100');
29
+ }
30
+ if (!Number.isInteger(count) || count < 1 || count > 1024) {
31
+ throw new RangeError('The GPU count has to be a whole number from 1 to 1024');
32
+ }
33
+ const seconds = Math.round(hours * 3600);
34
+ if (!Number.isFinite(hours) || seconds < 60 || hours > 24 * 7) {
35
+ throw new RangeError('The booking has to last from a minute to a week of hours, such as 1');
36
+ }
37
+ const windowStart = b.now + SANDBOX_STARTS_IN;
38
+ const windowDuration = BigInt(seconds);
39
+ const windowEnd = windowStart + windowDuration;
40
+ const half = windowDuration / 2n;
41
+ return gpuReservationTerms({
42
+ resource: { gpu, count, region: 'demo', sku: `demo-${gpu.toLowerCase()}x${count}` },
43
+ currency: 'USD',
44
+ windowStart,
45
+ windowDuration,
46
+ pricePerGpuHour: dollars(3),
47
+ freeCancelBy: windowStart - SANDBOX_STARTS_IN / 2n,
48
+ lateCancellation: b.reserve / 2n,
49
+ noShow: b.reserve,
50
+ gracePeriod: half < 2n * MINUTE ? half : 2n * MINUTE,
51
+ chargeDeadline: windowEnd,
52
+ contestWindow: 10n * MINUTE,
53
+ releaseDate: windowEnd,
54
+ arbiter: b.deployment.arbiter,
55
+ day90SupplierShareBps: b.deployment.day90SupplierShareBps,
56
+ });
57
+ }
58
+ //# sourceMappingURL=terms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terms.js","sourceRoot":"","sources":["../../src/sandbox/terms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type Address, type Hex } from 'viem';
2
+ /**
3
+ * The business's root key, sealed under a passphrase the developer sets. A process that reads the
4
+ * sealed file gets the key only by finding the passphrase, which PBKDF2 at 600,000 rounds makes slow
5
+ * to guess. It uses the platform's Web Crypto, PBKDF2 with SHA-256 to stretch the passphrase and
6
+ * AES-256-GCM to seal, so it runs the same in Node and in a browser.
7
+ */
8
+ export interface SealedKey {
9
+ kdf: 'PBKDF2-SHA256';
10
+ iterations: number;
11
+ salt: Hex;
12
+ cipher: 'AES-256-GCM';
13
+ iv: Hex;
14
+ ciphertext: Hex;
15
+ }
16
+ /** The fewest characters a passphrase can have. */
17
+ export declare const MIN_PASSPHRASE = 10;
18
+ /** Seals a private key under a passphrase, for the business account at `account`. */
19
+ export declare function sealKey(privateKey: Hex, passphrase: string, account: Address): Promise<SealedKey>;
20
+ /** Opens a sealed key with its passphrase, or throws when the passphrase doesn't open it. */
21
+ export declare function openKey(sealed: SealedKey, passphrase: string, account: Address): Promise<Hex>;
22
+ /** Whether some JSON is a sealed key in the form `sealKey` writes. */
23
+ export declare function isSealedKey(v: unknown): v is SealedKey;
24
+ //# sourceMappingURL=vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../src/sandbox/vault.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAc,KAAK,GAAG,EAAqB,MAAM,MAAM,CAAA;AAE5E;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,eAAe,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,GAAG,CAAA;IACT,MAAM,EAAE,aAAa,CAAA;IACrB,EAAE,EAAE,GAAG,CAAA;IACP,UAAU,EAAE,GAAG,CAAA;CAChB;AAED,mDAAmD;AACnD,eAAO,MAAM,cAAc,KAAK,CAAA;AA0BhC,qFAAqF;AACrF,wBAAsB,OAAO,CAC3B,UAAU,EAAE,GAAG,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,SAAS,CAAC,CAoBpB;AAED,6FAA6F;AAC7F,wBAAsB,OAAO,CAC3B,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,GAAG,CAAC,CAad;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,SAAS,CAWtD"}
@@ -0,0 +1,54 @@
1
+ import { bytesToHex, hexToBytes, isHex } from 'viem';
2
+ /** The fewest characters a passphrase can have. */
3
+ export const MIN_PASSPHRASE = 10;
4
+ /** How hard the passphrase is stretched, as OWASP's 2023 guidance sets for PBKDF2 with SHA-256. */
5
+ const ITERATIONS = 600_000;
6
+ /** What the sealed key is bound to, so a sealed key can't be passed off as another account's. */
7
+ const context = (account) => new TextEncoder().encode(`avow-sandbox-business-key:${account.toLowerCase()}`);
8
+ async function keyFrom(passphrase, salt, iterations) {
9
+ const material = await crypto.subtle.importKey('raw', new TextEncoder().encode(passphrase), 'PBKDF2', false, ['deriveKey']);
10
+ return crypto.subtle.deriveKey({ name: 'PBKDF2', hash: 'SHA-256', salt, iterations }, material, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']);
11
+ }
12
+ /** Seals a private key under a passphrase, for the business account at `account`. */
13
+ export async function sealKey(privateKey, passphrase, account) {
14
+ if (passphrase.length < MIN_PASSPHRASE) {
15
+ throw new RangeError(`The passphrase needs at least ${MIN_PASSPHRASE} characters`);
16
+ }
17
+ const salt = crypto.getRandomValues(new Uint8Array(16));
18
+ const iv = crypto.getRandomValues(new Uint8Array(12));
19
+ const key = await keyFrom(passphrase, salt, ITERATIONS);
20
+ const sealed = await crypto.subtle.encrypt({ name: 'AES-GCM', iv, additionalData: context(account) }, key, hexToBytes(privateKey));
21
+ return {
22
+ kdf: 'PBKDF2-SHA256',
23
+ iterations: ITERATIONS,
24
+ salt: bytesToHex(salt),
25
+ cipher: 'AES-256-GCM',
26
+ iv: bytesToHex(iv),
27
+ ciphertext: bytesToHex(new Uint8Array(sealed)),
28
+ };
29
+ }
30
+ /** Opens a sealed key with its passphrase, or throws when the passphrase doesn't open it. */
31
+ export async function openKey(sealed, passphrase, account) {
32
+ let opened;
33
+ try {
34
+ const key = await keyFrom(passphrase, hexToBytes(sealed.salt), sealed.iterations);
35
+ opened = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: hexToBytes(sealed.iv), additionalData: context(account) }, key, hexToBytes(sealed.ciphertext));
36
+ }
37
+ catch {
38
+ throw new Error("That passphrase doesn't open the business's key");
39
+ }
40
+ return bytesToHex(new Uint8Array(opened));
41
+ }
42
+ /** Whether some JSON is a sealed key in the form `sealKey` writes. */
43
+ export function isSealedKey(v) {
44
+ if (typeof v !== 'object' || v === null)
45
+ return false;
46
+ const s = v;
47
+ return (s.kdf === 'PBKDF2-SHA256' &&
48
+ s.cipher === 'AES-256-GCM' &&
49
+ typeof s.iterations === 'number' &&
50
+ Number.isInteger(s.iterations) &&
51
+ s.iterations >= 100_000 &&
52
+ [s.salt, s.iv, s.ciphertext].every((h) => typeof h === 'string' && isHex(h)));
53
+ }
54
+ //# sourceMappingURL=vault.js.map