@botanary/agent 0.1.0-alpha.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 (60) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +21 -0
  3. package/README.md +123 -0
  4. package/dist/errors.d.ts +49 -0
  5. package/dist/errors.d.ts.map +1 -0
  6. package/dist/errors.js +40 -0
  7. package/dist/errors.js.map +1 -0
  8. package/dist/exact-action.d.ts +48 -0
  9. package/dist/exact-action.d.ts.map +1 -0
  10. package/dist/exact-action.js +178 -0
  11. package/dist/exact-action.js.map +1 -0
  12. package/dist/fingerprint.d.ts +21 -0
  13. package/dist/fingerprint.d.ts.map +1 -0
  14. package/dist/fingerprint.js +47 -0
  15. package/dist/fingerprint.js.map +1 -0
  16. package/dist/generated/routes.d.ts +68 -0
  17. package/dist/generated/routes.d.ts.map +1 -0
  18. package/dist/generated/routes.js +92 -0
  19. package/dist/generated/routes.js.map +1 -0
  20. package/dist/generated/schema.d.ts +2903 -0
  21. package/dist/generated/schema.d.ts.map +1 -0
  22. package/dist/generated/schema.js +2 -0
  23. package/dist/generated/schema.js.map +1 -0
  24. package/dist/http-path.d.ts +92 -0
  25. package/dist/http-path.d.ts.map +1 -0
  26. package/dist/http-path.js +201 -0
  27. package/dist/http-path.js.map +1 -0
  28. package/dist/index.d.ts +11 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +7 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/pairing-code.d.ts +41 -0
  33. package/dist/pairing-code.d.ts.map +1 -0
  34. package/dist/pairing-code.js +60 -0
  35. package/dist/pairing-code.js.map +1 -0
  36. package/dist/registration.d.ts +21 -0
  37. package/dist/registration.d.ts.map +1 -0
  38. package/dist/registration.js +62 -0
  39. package/dist/registration.js.map +1 -0
  40. package/dist/runtime.d.ts +203 -0
  41. package/dist/runtime.d.ts.map +1 -0
  42. package/dist/runtime.js +559 -0
  43. package/dist/runtime.js.map +1 -0
  44. package/dist/signer.d.ts +33 -0
  45. package/dist/signer.d.ts.map +1 -0
  46. package/dist/signer.js +13 -0
  47. package/dist/signer.js.map +1 -0
  48. package/dist/transport.d.ts +13 -0
  49. package/dist/transport.d.ts.map +1 -0
  50. package/dist/transport.js +135 -0
  51. package/dist/transport.js.map +1 -0
  52. package/dist/validation.d.ts +15 -0
  53. package/dist/validation.d.ts.map +1 -0
  54. package/dist/validation.js +108 -0
  55. package/dist/validation.js.map +1 -0
  56. package/dist/views.d.ts +182 -0
  57. package/dist/views.d.ts.map +1 -0
  58. package/dist/views.js +2 -0
  59. package/dist/views.js.map +1 -0
  60. package/package.json +50 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.js","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAqBrD,wGAAwG;AACxG,MAAM,UAAU,qBAAqB,CAAC,OAKrC,EAAE,UAAoD,EAAE;IACvD,MAAM,QAAQ,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS;QACvE,WAAW,EAAE,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,UAAU;QACvF,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IAC7D,OAAO;QACL,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC;QACrC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;QACjD,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;KACzC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ /** Injection seam for an existing host transport. It receives only public payloads and agent tokens. */
2
+ export interface AgentTransport {
3
+ get<T>(path: string, token?: string): Promise<T>;
4
+ post<T>(path: string, body: unknown, token?: string): Promise<T>;
5
+ }
6
+ /** No mutation retries. A failed relay must be reconciled using its existing operation/hash. */
7
+ export declare class AgentApiClient implements AgentTransport {
8
+ #private;
9
+ constructor(baseUrl: string, fetchImpl?: typeof fetch);
10
+ get<T>(path: string, token?: string): Promise<T>;
11
+ post<T>(path: string, body: unknown, token?: string): Promise<T>;
12
+ }
13
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAMA,wGAAwG;AACxG,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAClE;AAED,gGAAgG;AAChG,qBAAa,cAAe,YAAW,cAAc;;gBAEvC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,OAAO,KAAa;IAS5D,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CAuDjE"}
@@ -0,0 +1,135 @@
1
+ import createClient from 'openapi-fetch';
2
+ import { AGENT_ROUTES } from './generated/routes.js';
3
+ import { canonicalizeHttpPath } from './http-path.js';
4
+ import { BotanaryApiError } from './errors.js';
5
+ /** No mutation retries. A failed relay must be reconciled using its existing operation/hash. */
6
+ export class AgentApiClient {
7
+ #client;
8
+ constructor(baseUrl, fetchImpl = fetch) {
9
+ const url = new URL(baseUrl);
10
+ if (url.username || url.password || url.search || url.hash || url.pathname !== '/' ||
11
+ (url.protocol !== 'https:' && !(url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)))) {
12
+ throw new Error('Agent API origin must be HTTPS, or HTTP on loopback.');
13
+ }
14
+ this.#client = createClient({ baseUrl: url.origin + '/v1', fetch: boundedFetch(fetchImpl) });
15
+ }
16
+ get(path, token) { return this.#request('get', path, undefined, token); }
17
+ post(path, body, token) { return this.#request('post', path, body, token); }
18
+ async #request(method, path, body, token) {
19
+ const canonical = canonicalizeHttpPath(path);
20
+ if (!canonical?.path.startsWith('/v1/'))
21
+ throw new Error('Invalid agent API path.');
22
+ if (token !== undefined && !/^ags_[a-f0-9]{64}$/.test(token))
23
+ throw new Error('Expected an agent session credential.');
24
+ const cleanPath = canonical.path.slice(3);
25
+ const route = AGENT_ROUTES.find(row => row.method === method &&
26
+ new RegExp('^' + row.path.replace(/\{[^}]+\}/g, '[A-Za-z0-9_-]+') + '$').test(cleanPath));
27
+ if (!route)
28
+ throw new Error('This route is outside the reviewed agent API.');
29
+ const parameters = {};
30
+ route.path.split('/').forEach((part, index) => {
31
+ if (part.startsWith('{'))
32
+ parameters[part.slice(1, -1)] = cleanPath.split('/')[index];
33
+ });
34
+ const query = Object.fromEntries(new URLSearchParams(canonical.query));
35
+ const controller = new AbortController();
36
+ const timeout = setTimeout(() => controller.abort(), 30_000);
37
+ try {
38
+ const result = await this.#client.request(method, route.path, {
39
+ params: { path: parameters, query },
40
+ ...(body === undefined ? {} : { body }),
41
+ headers: token ? { authorization: `Bearer ${token}` } : {},
42
+ credentials: 'omit', redirect: 'error', cache: 'no-store', signal: controller.signal,
43
+ parseAs: 'text',
44
+ });
45
+ const response = result.response;
46
+ let data = result.error;
47
+ if (response.ok) {
48
+ try {
49
+ data = result.data ? JSON.parse(result.data) : {};
50
+ }
51
+ catch {
52
+ throw new Error('Invalid JSON response.');
53
+ }
54
+ }
55
+ if (!response.ok) {
56
+ const error = record(record(data)?.error);
57
+ const message = typeof error?.message === 'string' ? error.message : `Agent request failed with ${response.status}.`;
58
+ const redacted = message.replace(/(?:bsk_(?:test|live)|ags|dcs|dca|dcr)_[A-Za-z0-9_-]+/g, '[redacted]').replace(/0x[a-fA-F0-9]{64,}/g, '[redacted]');
59
+ const retry = response.headers.get('retry-after');
60
+ const retrySeconds = retry && /^\d+(?:\.\d+)?$/.test(retry) ? Number(retry) : null;
61
+ // Keep only actionable, non-secret fields. The response body and request never enter errors.
62
+ const details = record(error?.details);
63
+ const safeDetails = details && Object.fromEntries(Object.entries(details).filter(([key, value]) => ['missingModule', 'declineReason', 'chainId'].includes(key) && (typeof value === 'number' || (typeof value === 'string' && /^[a-zA-Z0-9_-]{1,100}$/.test(value)))));
64
+ const failure = new BotanaryApiError(redacted.slice(0, 1000), response.status, safeDetails, retrySeconds);
65
+ failure.requestId = safeId(response.headers.get('x-request-id'));
66
+ failure.code = safeId(error?.code) ?? 'http_error';
67
+ failure.ambiguous = method === 'post' && response.status >= 500;
68
+ throw failure;
69
+ }
70
+ return data;
71
+ }
72
+ catch (error) {
73
+ if (error instanceof BotanaryApiError)
74
+ throw error;
75
+ const failure = new BotanaryApiError('The agent request did not complete. Check the existing operation before retrying.', 0);
76
+ failure.code = controller.signal.aborted ? 'timeout' : 'transport_error';
77
+ failure.ambiguous = method === 'post';
78
+ throw failure;
79
+ }
80
+ finally {
81
+ clearTimeout(timeout);
82
+ }
83
+ }
84
+ }
85
+ function record(value) {
86
+ return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : null;
87
+ }
88
+ function safeId(value) {
89
+ return typeof value === 'string' && /^[a-zA-Z0-9_-]{1,128}$/.test(value) && !/^(?:ags|bsk|dcs|dca|dcr)_/.test(value) ? value : undefined;
90
+ }
91
+ function boundedFetch(fetchImpl) {
92
+ return async (input, init) => {
93
+ const request = input instanceof Request ? input : new Request(input, init);
94
+ const signal = request.signal;
95
+ let cancel = () => { };
96
+ const aborted = new Promise((_, reject) => {
97
+ cancel = () => reject(new Error('Request aborted.'));
98
+ if (signal.aborted)
99
+ cancel();
100
+ else
101
+ signal.addEventListener('abort', cancel, { once: true });
102
+ });
103
+ let reader;
104
+ try {
105
+ const response = await Promise.race([fetchImpl(request), aborted]);
106
+ if (!response.body)
107
+ return response;
108
+ reader = response.body.getReader();
109
+ const chunks = [];
110
+ let size = 0;
111
+ while (true) {
112
+ const part = await Promise.race([reader.read(), aborted]);
113
+ if (part.done)
114
+ break;
115
+ size += part.value.byteLength;
116
+ if (size > 4 * 1024 * 1024)
117
+ throw new Error('Response too large.');
118
+ chunks.push(part.value);
119
+ }
120
+ const bytes = new Uint8Array(size);
121
+ let offset = 0;
122
+ for (const chunk of chunks) {
123
+ bytes.set(chunk, offset);
124
+ offset += chunk.byteLength;
125
+ }
126
+ return new Response(bytes, { status: response.status, statusText: response.statusText, headers: response.headers });
127
+ }
128
+ finally {
129
+ signal.removeEventListener('abort', cancel);
130
+ if (reader)
131
+ void reader.cancel().catch(() => { });
132
+ }
133
+ };
134
+ }
135
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { Hex } from 'viem';
2
+ import type { AgentIdentity } from './signer.js';
3
+ import type { ApiCallRequirementsReady, UnsignedUserOp } from './views.js';
4
+ export declare function invalidResponse(): never;
5
+ export declare function record(value: unknown): Record<string, unknown>;
6
+ export declare function hex(value: unknown, bytes?: number): asserts value is Hex;
7
+ export declare function resourceId(value: unknown): asserts value is string;
8
+ export declare function publicIdentity(value: unknown): AgentIdentity;
9
+ /** The public v0.7 contract permits decimal or hex integer quantities. Bytes remain hex-only. */
10
+ export declare function userOpQuantity(value: unknown, bits?: number): bigint;
11
+ export declare function unsignedUserOp(value: unknown): UnsignedUserOp;
12
+ export declare function readyRequirement(value: unknown): Pick<ApiCallRequirementsReady, 'payload' | 'authorization' | 'index' | 'validator'>;
13
+ /** Bind a recovery response to the requested handle; never treat provider success as payment proof. */
14
+ export declare function apiCallStatus(value: unknown, requirementId: string): Record<string, unknown>;
15
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3E,wBAAgB,eAAe,IAAI,KAAK,CAIvC;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAG9D;AACD,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,GAAG,CAExE;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAElE;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAU5D;AACD,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAM,GAAG,MAAM,CAKjE;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAU7D;AACD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC,wBAAwB,EAAE,SAAS,GAAG,eAAe,GAAG,OAAO,GAAG,WAAW,CAAC,CAWpI;AAED,uGAAuG;AACvG,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAY5F"}
@@ -0,0 +1,108 @@
1
+ import { publicKeyToAddress } from 'viem/accounts';
2
+ import { BotanaryApiError } from './errors.js';
3
+ export function invalidResponse() {
4
+ const error = new BotanaryApiError('Botanary returned an invalid response. Nothing was signed.', 0);
5
+ error.code = 'invalid_response';
6
+ throw error;
7
+ }
8
+ export function record(value) {
9
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
10
+ return invalidResponse();
11
+ return value;
12
+ }
13
+ export function hex(value, bytes) {
14
+ if (typeof value !== 'string' || !/^0x(?:[0-9a-fA-F]{2})*$/.test(value) || (bytes !== undefined && value.length !== 2 + 2 * bytes))
15
+ invalidResponse();
16
+ }
17
+ export function resourceId(value) {
18
+ if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/.test(value) || /^(?:bsk|ags|dcs|dca|dcr)_/.test(value))
19
+ invalidResponse();
20
+ }
21
+ function uint(value) {
22
+ if (typeof value !== 'string' || !/^(0|[1-9][0-9]{0,77})$/.test(value) || BigInt(value) >= 2n ** 256n)
23
+ invalidResponse();
24
+ }
25
+ export function publicIdentity(value) {
26
+ const row = record(value);
27
+ hex(row.address, 20);
28
+ hex(row.publicKey, 65);
29
+ if (!row.publicKey.startsWith('0x04') || publicKeyToAddress(row.publicKey).toLowerCase() !== row.address.toLowerCase() ||
30
+ typeof row.fingerprint !== 'string' || !/^[A-Za-z0-9]{1,32}$/.test(row.fingerprint) ||
31
+ typeof row.backend !== 'string' || !/^[A-Za-z0-9_-]{1,64}$/.test(row.backend) ||
32
+ typeof row.createdAt !== 'string' || !Number.isFinite(Date.parse(row.createdAt)))
33
+ invalidResponse();
34
+ // Copy only public fields. A custom signer returning extra fields cannot leak them via identity().
35
+ return Object.freeze({ address: row.address, publicKey: row.publicKey, fingerprint: row.fingerprint,
36
+ backend: row.backend, createdAt: row.createdAt });
37
+ }
38
+ /** The public v0.7 contract permits decimal or hex integer quantities. Bytes remain hex-only. */
39
+ export function userOpQuantity(value, bits = 256) {
40
+ if (typeof value !== 'string' || !/^(0|[1-9][0-9]{0,77}|0x[0-9a-fA-F]{1,64})$/.test(value))
41
+ return invalidResponse();
42
+ const result = BigInt(value);
43
+ if (result >= 2n ** BigInt(bits))
44
+ return invalidResponse();
45
+ return result;
46
+ }
47
+ export function unsignedUserOp(value) {
48
+ const row = record(value);
49
+ for (const name of ['sender', 'entryPoint'])
50
+ hex(row[name], 20);
51
+ for (const name of ['nonce', 'callGasLimit', 'verificationGasLimit', 'preVerificationGas', 'maxFeePerGas', 'maxPriorityFeePerGas'])
52
+ userOpQuantity(row[name]);
53
+ for (const name of ['callData', 'signature'])
54
+ hex(row[name]);
55
+ for (const name of ['paymasterVerificationGasLimit', 'paymasterPostOpGasLimit'])
56
+ if (row[name] != null)
57
+ userOpQuantity(row[name], 128);
58
+ if (!Number.isSafeInteger(row.chainId) || Number(row.chainId) <= 0)
59
+ invalidResponse();
60
+ for (const name of ['factory', 'paymaster'])
61
+ if (row[name] != null)
62
+ hex(row[name], 20);
63
+ for (const name of ['factoryData', 'paymasterData'])
64
+ if (row[name] != null)
65
+ hex(row[name]);
66
+ return value;
67
+ }
68
+ export function readyRequirement(value) {
69
+ const row = record(value);
70
+ hex(row.payload, 32);
71
+ hex(row.validator, 20);
72
+ if (!Number.isSafeInteger(row.index) || Number(row.index) < 0 || Number(row.index) >= 2 ** 32)
73
+ invalidResponse();
74
+ const auth = record(row.authorization);
75
+ hex(auth.from, 20);
76
+ hex(auth.to, 20);
77
+ hex(auth.nonce, 32);
78
+ uint(auth.value);
79
+ uint(auth.validAfter);
80
+ uint(auth.validBefore);
81
+ if (BigInt(auth.validBefore) <= BigInt(auth.validAfter))
82
+ invalidResponse();
83
+ return { payload: row.payload, validator: row.validator, index: Number(row.index), authorization: {
84
+ from: auth.from, to: auth.to, nonce: auth.nonce, value: auth.value, validAfter: auth.validAfter, validBefore: auth.validBefore,
85
+ } };
86
+ }
87
+ /** Bind a recovery response to the requested handle; never treat provider success as payment proof. */
88
+ export function apiCallStatus(value, requirementId) {
89
+ const row = record(value);
90
+ if (row.requirementId !== requirementId || typeof row.simulated !== 'boolean')
91
+ invalidResponse();
92
+ const expected = { ready: ['not_submitted'], pending_approval: ['not_submitted'],
93
+ submitted: ['pending'], settled: ['settled'], declined: ['not_submitted', 'not_settled'] };
94
+ if (typeof row.status !== 'string' || !Object.hasOwn(expected, row.status) || !expected[row.status].includes(String(row.paymentStatus)))
95
+ invalidResponse();
96
+ if (row.providerStatus !== undefined && (!Number.isSafeInteger(row.providerStatus) || Number(row.providerStatus) < 100 || Number(row.providerStatus) > 599))
97
+ invalidResponse();
98
+ if (row.txHash !== undefined)
99
+ hex(row.txHash, 32);
100
+ if (row.status === 'settled')
101
+ hex(row.txHash, 32);
102
+ if (row.status === 'ready')
103
+ readyRequirement(row.ready);
104
+ else if (row.ready !== undefined)
105
+ invalidResponse();
106
+ return row;
107
+ }
108
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,182 @@
1
+ import type { Hex } from 'viem';
2
+ import type { components } from './generated/schema.js';
3
+ type HexFields<T> = {
4
+ [K in keyof T]: K extends 'sender' | 'entryPoint' | 'callData' | 'signature' | 'factory' | 'factoryData' | 'paymaster' | 'paymasterData' ? Hex | Extract<T[K], null | undefined> : T[K];
5
+ };
6
+ export type UnsignedUserOp = HexFields<components['schemas']['UnsignedUserOp']>;
7
+ /** An UNSIGNED userOp build response shape (`POST /delegations/{delegationId}/actions`, the ONLY build
8
+ * lane whose op a session-key signature can actually validate - see `buildDelegatedAction`'s own doc
9
+ * comment) - the UserOp wire fields are generated from the reviewed API contract. Compatibility views below
10
+ * retain the historical MCP fields while the transport contract supplies the complete wire types. */
11
+ export interface UserOpBuildResult {
12
+ intentType: string;
13
+ userOp: UnsignedUserOp;
14
+ userOpHash: Hex;
15
+ [key: string]: unknown;
16
+ }
17
+ /** One entry of `AgentSelf.grant.policySet.spentToDate` (backend's `SpendMeter`) - what tells a caller
18
+ * how much of a budgeted token is left before it tries to spend more than a grant allows. */
19
+ export interface SpendMeterView {
20
+ token: {
21
+ symbol: string;
22
+ chainId?: number | null;
23
+ address?: string | null;
24
+ assetRef?: string | null;
25
+ };
26
+ limit: number;
27
+ spent: number;
28
+ remaining: number;
29
+ expiresAt?: string | null;
30
+ }
31
+ /** The SWAP venue a grant pins, when it was granted swap authority at all (backend's
32
+ * `PolicySet.swapVenue`). ABSENT - not null - on a transfer-only grant, which is exactly what makes it
33
+ * answerable: the compiled Smart Sessions session is not readable back from a `permissionId`, so this
34
+ * recorded fact is the only way either side can know whether the session carries an allowance action.
35
+ * `maxAllowance` is DISPLAY units (the backend scales it by the token's own resolution), so it compares
36
+ * directly against `propose_swap`'s `amountIn`. */
37
+ export interface GrantSwapVenueView {
38
+ /** The one router this grant may approve AND call - the allowance entrypoint has one `(token, target)`. */
39
+ router: string;
40
+ /** The one token this grant may sell. */
41
+ token: {
42
+ symbol: string;
43
+ chainId?: number | null;
44
+ address?: string | null;
45
+ };
46
+ /** Ceiling on a SINGLE swap's allowance, in display units. Not a budget: the grant's own budget meters
47
+ * separately, and both apply. */
48
+ maxAllowance: number;
49
+ }
50
+ /** The live grant `GET /agents/me` reports, when one exists - mirrors the backend's `Delegation` (only
51
+ * the fields this package reads). */
52
+ export interface AgentGrantView {
53
+ id: string;
54
+ permissionId: Hex;
55
+ status: string;
56
+ humanSummary: string;
57
+ chain: string;
58
+ chainId: number;
59
+ policySet: {
60
+ /** `token.assetRef` is stamped on at READ time by the backend's `withGrantAssetRefs`
61
+ * (`grant-asset-refs.ts`) - CAIP-19, e.g. `eip155:8453/erc20:0x...` - and is what
62
+ * `findBudgetMeter`/`checkSendBounds` match a resolved send against, never the symbol. `null`
63
+ * means this build could not resolve an on-chain address for the token (honestly undecodable,
64
+ * never guessed); absent (older backend) means "not reported". */
65
+ budgets: Array<{
66
+ token: {
67
+ symbol: string;
68
+ chainId?: number | null;
69
+ assetRef?: string | null;
70
+ };
71
+ amount: number;
72
+ }>;
73
+ perActionMax?: {
74
+ token: {
75
+ symbol: string;
76
+ chainId?: number | null;
77
+ assetRef?: string | null;
78
+ };
79
+ amount: number;
80
+ } | null;
81
+ recipientAllowlist?: Array<{
82
+ address: string;
83
+ name?: string | null;
84
+ }>;
85
+ expiresAt?: string | null;
86
+ /** Absent unless this grant was given swap authority - see `GrantSwapVenueView`. */
87
+ swapVenue?: GrantSwapVenueView | null;
88
+ [key: string]: unknown;
89
+ };
90
+ spentToDate: SpendMeterView[];
91
+ [key: string]: unknown;
92
+ }
93
+ /** `GET /agents/me`'s response - who this agent is, what account it is bound to, and its live grant if
94
+ * any. `grant: null` is an honest, explicit answer (see agents.controller.ts's own doc comment), never
95
+ * an error and never fabricated by this package. */
96
+ export interface AgentSelf {
97
+ id: string;
98
+ name: string;
99
+ address: Hex;
100
+ fingerprint: string;
101
+ connectedAt: string;
102
+ accountId: string;
103
+ /** The bound account's own on-chain address - the one identifier the owner actually recognises, since
104
+ * `accountId` is an opaque row id that appears nowhere in the Botanary app. Without it, an agent
105
+ * paired to a DIFFERENT login than the one the owner has open reports itself connected and gives
106
+ * them nothing to notice the mismatch with. Optional here because an older backend does not send it;
107
+ * this package never fabricates one. */
108
+ accountAddress?: Hex | null;
109
+ grant: AgentGrantView | null;
110
+ /** Whether the grant's own chain has every setup module the account needs. Optional because an older
111
+ * backend does not send it - absent means "not reported", which this package treats as "no evidence
112
+ * of a problem" rather than inventing either answer. */
113
+ accountSetup?: {
114
+ ready: boolean;
115
+ missing: string[];
116
+ chainId: number;
117
+ } | null;
118
+ }
119
+ /** A submitted call, exactly the shape `POST /agents/requests`'s `calls` field and a money/swap build's
120
+ * own callData/value/to already share. */
121
+ export interface UnsignedCallView {
122
+ to: string;
123
+ data: string;
124
+ value: string;
125
+ chainId: number;
126
+ }
127
+ /** `POST /agents/requests`'s response - the raised request, including which bound was crossed and the
128
+ * deadline, exactly as the backend reports them (never fabricated here). */
129
+ export interface AgentRequestView {
130
+ id: string;
131
+ agentId: string;
132
+ accountId: string;
133
+ calls: UnsignedCallView[];
134
+ declineReason: string;
135
+ reason: string;
136
+ raisedAt: string;
137
+ expiresAt: string;
138
+ status: string;
139
+ [key: string]: unknown;
140
+ }
141
+ /** The exact EIP-3009 tuple this lane's `X402PaymentValidator` verifies, field order load-bearing - it
142
+ * must match `IX402PaymentValidator.Authorization` in botanary-contracts exactly (reorder a field and
143
+ * every signature stops verifying; see that interface's own doc comment). Decimal-string value fields,
144
+ * mirroring the backend's own `X402Authorization` wire shape (`src/modules/x402/x402-authorization.ts`)
145
+ * rather than a bigint: JSON has no integer wide enough for a uint256, and this package never imports
146
+ * across the BE boundary to reuse that type directly (deploy-isolated - see the workspace AGENTS.md). */
147
+ export interface X402AuthorizationView {
148
+ from: Hex;
149
+ to: Hex;
150
+ value: string;
151
+ validAfter: string;
152
+ validBefore: string;
153
+ nonce: Hex;
154
+ [key: string]: unknown;
155
+ }
156
+ /** `POST /apis/calls/requirements`'s `ready` branch (Task 13) - everything `callApi` needs to build the
157
+ * Kernel ERC-1271 envelope. `validator` is the `X402PaymentValidator` address on THIS call's chain,
158
+ * read from here and never hardcoded: deployment addresses are nonce-shifted between chains, so the
159
+ * same address means something different on another chain. */
160
+ export interface ApiCallRequirementsReady {
161
+ requirementId: string;
162
+ status: 'ready';
163
+ payload: Hex;
164
+ authorization: X402AuthorizationView;
165
+ index: number;
166
+ validator: Hex;
167
+ [key: string]: unknown;
168
+ }
169
+ /** `POST /apis/calls/requirements`'s `pending_approval` branch (Task 11's confirmation threshold) -
170
+ * carries NONE of `payload`/`authorization`/`index`/`validator`, structurally, not merely empty: the
171
+ * digest is deliberately withheld until the owner answers. `callApi` must never try to sign off this
172
+ * shape - see its own handling below. */
173
+ export interface ApiCallRequirementsPending {
174
+ requirementId: string;
175
+ status: 'pending_approval';
176
+ approvalId: string;
177
+ expiresAt: string;
178
+ [key: string]: unknown;
179
+ }
180
+ export type ApiCallRequirementsResponse = ApiCallRequirementsReady | ApiCallRequirementsPending;
181
+ export {};
182
+ //# sourceMappingURL=views.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"views.d.ts","sourceRoot":"","sources":["../src/views.ts"],"names":[],"mappings":"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"}
package/dist/views.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=views.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"views.js","sourceRoot":"","sources":["../src/views.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@botanary/agent",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "Botanary agent session and execution runtime with an injected signer",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22"
9
+ },
10
+ "packageManager": "pnpm@11.5.1",
11
+ "sideEffects": false,
12
+ "files": [
13
+ "dist",
14
+ "README.md",
15
+ "CHANGELOG.md",
16
+ "LICENSE"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./types": {
24
+ "types": "./dist/generated/schema.d.ts"
25
+ }
26
+ },
27
+ "scripts": {
28
+ "generate": "node scripts/generate.mjs",
29
+ "check:generated": "node scripts/generate.mjs --check",
30
+ "typecheck": "tsc --noEmit",
31
+ "build": "tsc",
32
+ "test": "vitest run",
33
+ "prepack": "pnpm check:generated && pnpm typecheck && pnpm build",
34
+ "test:packed": "node scripts/verify-packed.mjs"
35
+ },
36
+ "dependencies": {
37
+ "openapi-fetch": "0.17.0",
38
+ "viem": "2.54.6"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "22.19.15",
42
+ "openapi-typescript": "7.13.0",
43
+ "typescript": "5.9.3",
44
+ "vitest": "2.1.9",
45
+ "yaml": "2.9.0"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ }
50
+ }