@aexhq/sdk 0.54.1 → 0.55.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 (57) hide show
  1. package/README.md +16 -123
  2. package/dist/errors.d.ts +33 -0
  3. package/dist/errors.js +69 -0
  4. package/dist/index.d.ts +16 -23
  5. package/dist/index.js +18 -16
  6. package/dist/json.d.ts +4 -0
  7. package/dist/json.js +46 -0
  8. package/dist/session.d.ts +74 -0
  9. package/dist/session.js +255 -0
  10. package/dist/transport.d.ts +22 -0
  11. package/dist/transport.js +196 -0
  12. package/package.json +16 -64
  13. package/LICENSE +0 -201
  14. package/NOTICE +0 -38
  15. package/dist/client/aex.d.ts +0 -38
  16. package/dist/client/aex.js +0 -149
  17. package/dist/client/aex.js.map +0 -1
  18. package/dist/client/credentials.d.ts +0 -25
  19. package/dist/client/credentials.js +0 -97
  20. package/dist/client/credentials.js.map +0 -1
  21. package/dist/client/routing.d.ts +0 -7
  22. package/dist/client/routing.js +0 -26
  23. package/dist/client/routing.js.map +0 -1
  24. package/dist/downloads/download.d.ts +0 -18
  25. package/dist/downloads/download.js +0 -67
  26. package/dist/downloads/download.js.map +0 -1
  27. package/dist/files/workspace-files.d.ts +0 -55
  28. package/dist/files/workspace-files.js +0 -150
  29. package/dist/files/workspace-files.js.map +0 -1
  30. package/dist/generated/errors.d.ts +0 -12
  31. package/dist/generated/errors.js +0 -66
  32. package/dist/generated/errors.js.map +0 -1
  33. package/dist/generated/models.d.ts +0 -853
  34. package/dist/generated/models.js +0 -62
  35. package/dist/generated/models.js.map +0 -1
  36. package/dist/generated/resources.d.ts +0 -265
  37. package/dist/generated/resources.js +0 -207
  38. package/dist/generated/resources.js.map +0 -1
  39. package/dist/generated/routes.d.ts +0 -44
  40. package/dist/generated/routes.js +0 -510
  41. package/dist/generated/routes.js.map +0 -1
  42. package/dist/index.js.map +0 -1
  43. package/dist/observations/stream.d.ts +0 -1
  44. package/dist/observations/stream.js +0 -18
  45. package/dist/observations/stream.js.map +0 -1
  46. package/dist/transport/errors.d.ts +0 -60
  47. package/dist/transport/errors.js +0 -107
  48. package/dist/transport/errors.js.map +0 -1
  49. package/dist/transport/pagination.d.ts +0 -8
  50. package/dist/transport/pagination.js +0 -34
  51. package/dist/transport/pagination.js.map +0 -1
  52. package/dist/transport/retry.d.ts +0 -21
  53. package/dist/transport/retry.js +0 -37
  54. package/dist/transport/retry.js.map +0 -1
  55. package/dist/transport/transport.d.ts +0 -33
  56. package/dist/transport/transport.js +0 -111
  57. package/dist/transport/transport.js.map +0 -1
@@ -0,0 +1,255 @@
1
+ import * as z from "zod";
2
+ import { AbortError, OutputSchemaError, OutputValidationError, SessionError, abortError, errorFromApi, } from "./errors.js";
3
+ import { jcsSha256, randomIdempotencyKey } from "./json.js";
4
+ export class Sessions {
5
+ #transport;
6
+ constructor(transport) {
7
+ this.#transport = transport;
8
+ }
9
+ async create(options, request = {}) {
10
+ const body = {
11
+ model: {
12
+ provider: options.model.provider,
13
+ name: options.model.name,
14
+ api_key: options.model.apiKey,
15
+ ...(options.model.baseUrl === undefined ? {} : { base_url: options.model.baseUrl }),
16
+ ...(options.model.maxOutputTokens === undefined
17
+ ? {}
18
+ : { max_output_tokens: options.model.maxOutputTokens }),
19
+ ...(options.model.temperature === undefined ? {} : { temperature: options.model.temperature }),
20
+ ...(options.model.reasoningEffort === undefined
21
+ ? {}
22
+ : { reasoning_effort: options.model.reasoningEffort }),
23
+ },
24
+ ...(options.systemPrompt === undefined ? {} : { system_prompt: options.systemPrompt }),
25
+ ...(options.metadata === undefined ? {} : { metadata: options.metadata }),
26
+ };
27
+ const data = await this.#transport.json("POST", "/v1/sessions", {
28
+ body,
29
+ headers: { "Idempotency-Key": request.idempotencyKey ?? randomIdempotencyKey() },
30
+ signal: request.signal,
31
+ retry: true,
32
+ });
33
+ return new Session(this.#transport, data);
34
+ }
35
+ async get(id, options = {}) {
36
+ const data = await this.#transport.json("GET", `/v1/sessions/${encodeURIComponent(id)}`, { signal: options.signal });
37
+ return new Session(this.#transport, data);
38
+ }
39
+ async list(options = {}) {
40
+ const query = new URLSearchParams();
41
+ if (options.limit !== undefined)
42
+ query.set("limit", String(options.limit));
43
+ if (options.cursor !== undefined)
44
+ query.set("cursor", options.cursor);
45
+ if (options.state !== undefined)
46
+ query.set("state", options.state);
47
+ const suffix = query.size === 0 ? "" : `?${query}`;
48
+ const list = await this.#transport.json("GET", `/v1/sessions${suffix}`, {
49
+ signal: options.signal,
50
+ });
51
+ return {
52
+ data: list.data.map((data) => new Session(this.#transport, data)),
53
+ hasMore: list.has_more,
54
+ ...(list.next_cursor === undefined ? {} : { nextCursor: list.next_cursor }),
55
+ };
56
+ }
57
+ }
58
+ export class Session {
59
+ #transport;
60
+ #data;
61
+ constructor(transport, data) {
62
+ this.#transport = transport;
63
+ this.#data = data;
64
+ }
65
+ get id() {
66
+ return this.#data.id;
67
+ }
68
+ get state() {
69
+ return this.#data.state;
70
+ }
71
+ get model() {
72
+ return {
73
+ provider: this.#data.model.provider,
74
+ name: this.#data.model.name,
75
+ ...(this.#data.model.base_url === undefined ? {} : { baseUrl: this.#data.model.base_url }),
76
+ };
77
+ }
78
+ get createdAt() {
79
+ return this.#data.created_at;
80
+ }
81
+ get updatedAt() {
82
+ return this.#data.updated_at;
83
+ }
84
+ get metadata() {
85
+ return this.#data.metadata;
86
+ }
87
+ async refresh(options = {}) {
88
+ this.#data = await this.#transport.json("GET", `/v1/sessions/${encodeURIComponent(this.id)}`, { signal: options.signal });
89
+ return this;
90
+ }
91
+ async send(input, options = {}) {
92
+ const accepted = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/messages`, {
93
+ body: {
94
+ content: input,
95
+ ...(options.metadata === undefined ? {} : { metadata: options.metadata }),
96
+ },
97
+ headers: { "Idempotency-Key": options.idempotencyKey ?? randomIdempotencyKey() },
98
+ signal: options.signal,
99
+ retry: true,
100
+ });
101
+ let answer = "";
102
+ try {
103
+ for await (const event of this.events({ after: Math.max(0, accepted.seq - 1), signal: options.signal })) {
104
+ if (event.type === "assistant.message" && event.turn_id === accepted.turn_id && event.agent_id === "root") {
105
+ answer = event.text;
106
+ }
107
+ else if (event.type === "turn.failed" && event.turn_id === accepted.turn_id) {
108
+ throw errorFromApi(event.error);
109
+ }
110
+ else if (event.type === "turn.completed" && event.turn_id === accepted.turn_id) {
111
+ this.markIdle();
112
+ if (event.stop_reason === "cancelled")
113
+ throw new AbortError();
114
+ return answer;
115
+ }
116
+ }
117
+ }
118
+ catch (error) {
119
+ if (options.signal?.aborted === true)
120
+ throw abortError(error);
121
+ throw error;
122
+ }
123
+ throw new SessionError("The Aex event stream ended before the session finished its work");
124
+ }
125
+ async output(schema, input, options = {}) {
126
+ let jsonSchema;
127
+ try {
128
+ assertPortableOutputSchema(schema);
129
+ jsonSchema = z.toJSONSchema(schema, {
130
+ target: "draft-2020-12",
131
+ unrepresentable: "throw",
132
+ });
133
+ }
134
+ catch (cause) {
135
+ throw new OutputSchemaError(messageOf(cause, "The Zod schema cannot be represented as JSON Schema"), {
136
+ cause,
137
+ });
138
+ }
139
+ if (jsonSchema.type !== "object") {
140
+ throw new OutputSchemaError("session.output() requires a Zod object schema");
141
+ }
142
+ const schemaHash = await jcsSha256(jsonSchema);
143
+ const body = {
144
+ schema: jsonSchema,
145
+ schema_hash: schemaHash,
146
+ ...(input === undefined ? {} : { input }),
147
+ ...(options.metadata === undefined ? {} : { metadata: options.metadata }),
148
+ };
149
+ const accepted = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/output`, {
150
+ body,
151
+ headers: { "Idempotency-Key": options.idempotencyKey ?? randomIdempotencyKey() },
152
+ signal: options.signal,
153
+ retry: true,
154
+ });
155
+ if (accepted.session_id !== this.id || accepted.schema_hash !== schemaHash) {
156
+ throw new SessionError("Aex returned an inconsistent output admission");
157
+ }
158
+ try {
159
+ for await (const event of this.events({ after: Math.max(0, accepted.seq - 1), signal: options.signal })) {
160
+ if (event.type === "output.failed" && event.output_id === accepted.output_id) {
161
+ if (event.schema_hash !== schemaHash) {
162
+ throw new SessionError("Aex returned an output failure for a different schema");
163
+ }
164
+ this.markIdle();
165
+ throw outputEventError(event.error, event.issues);
166
+ }
167
+ if (event.type === "output.completed" && event.output_id === accepted.output_id) {
168
+ if (event.output.schema_hash !== schemaHash) {
169
+ throw new SessionError("Aex returned an output value for a different schema");
170
+ }
171
+ this.markIdle();
172
+ const parsed = await schema.safeParseAsync(event.output.value);
173
+ if (!parsed.success) {
174
+ throw new OutputValidationError("The output passed the wire schema but failed the original Zod schema", parsed.error.issues.map((issue) => ({
175
+ path: jsonPointer(issue.path),
176
+ message: issue.message,
177
+ keyword: issue.code,
178
+ })));
179
+ }
180
+ return parsed.data;
181
+ }
182
+ }
183
+ }
184
+ catch (error) {
185
+ if (options.signal?.aborted === true) {
186
+ await this.cancel().catch(() => undefined);
187
+ throw abortError(error);
188
+ }
189
+ throw error;
190
+ }
191
+ throw new SessionError("The Aex event stream ended before the typed output completed");
192
+ }
193
+ events(options = {}) {
194
+ return this.#transport.events(this.id, options);
195
+ }
196
+ async cancel(options = {}) {
197
+ this.#data = await this.#transport.json("POST", `/v1/sessions/${encodeURIComponent(this.id)}/cancel`, { signal: options.signal });
198
+ return this;
199
+ }
200
+ async delete(options = {}) {
201
+ await this.#transport.json("DELETE", `/v1/sessions/${encodeURIComponent(this.id)}`, {
202
+ signal: options.signal,
203
+ });
204
+ this.#data = { ...this.#data, state: "deleted" };
205
+ }
206
+ markIdle() {
207
+ this.#data = { ...this.#data, state: "idle" };
208
+ }
209
+ }
210
+ function outputEventError(error, issues) {
211
+ return errorFromApi(error, undefined, issues ?? []);
212
+ }
213
+ function jsonPointer(path) {
214
+ if (path.length === 0)
215
+ return "";
216
+ return `/${path
217
+ .map((part) => String(part).replaceAll("~", "~0").replaceAll("/", "~1"))
218
+ .join("/")}`;
219
+ }
220
+ function messageOf(error, fallback) {
221
+ return error instanceof Error && error.message !== "" ? error.message : fallback;
222
+ }
223
+ /**
224
+ * A server cannot execute user-defined Zod functions. Reject them before admission instead of
225
+ * committing a value that only the calling process can later discover was invalid.
226
+ */
227
+ function assertPortableOutputSchema(schema) {
228
+ const seen = new WeakSet();
229
+ const visit = (value) => {
230
+ if (value === null || typeof value !== "object" || seen.has(value))
231
+ return;
232
+ seen.add(value);
233
+ const internal = value;
234
+ if (internal._zod?.def !== undefined) {
235
+ const definition = internal._zod.def;
236
+ const unsupported = definition.type === "custom" ||
237
+ definition.type === "transform" ||
238
+ definition.type === "file" ||
239
+ definition.check === "overwrite";
240
+ if (unsupported) {
241
+ throw new OutputSchemaError(`This Zod schema contains ${String(definition.type ?? definition.check)} behavior that cannot be enforced by the Aex output service`);
242
+ }
243
+ visit(definition);
244
+ return;
245
+ }
246
+ if (Array.isArray(value)) {
247
+ for (const item of value)
248
+ visit(item);
249
+ return;
250
+ }
251
+ for (const child of Object.values(value))
252
+ visit(child);
253
+ };
254
+ visit(schema);
255
+ }
@@ -0,0 +1,22 @@
1
+ import type { Event } from "@aexhq/contracts/session";
2
+ export type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
3
+ interface JsonRequestOptions {
4
+ body?: unknown;
5
+ headers?: Record<string, string>;
6
+ signal?: AbortSignal | undefined;
7
+ retry?: boolean;
8
+ }
9
+ export interface EventOptions {
10
+ after?: number;
11
+ follow?: boolean;
12
+ signal?: AbortSignal | undefined;
13
+ }
14
+ export declare class Transport {
15
+ #private;
16
+ readonly baseUrl: string;
17
+ constructor(apiKey: string, baseUrl: string, fetchImplementation: Fetch);
18
+ json<T>(method: "GET" | "POST" | "DELETE", path: string, options?: JsonRequestOptions): Promise<T>;
19
+ events(sessionId: string, options?: EventOptions): AsyncGenerator<Event>;
20
+ private responseError;
21
+ }
22
+ export {};
@@ -0,0 +1,196 @@
1
+ import { AbortError, AexError, SessionError, abortError, errorFromApi } from "./errors.js";
2
+ export class Transport {
3
+ baseUrl;
4
+ #apiKey;
5
+ #fetch;
6
+ constructor(apiKey, baseUrl, fetchImplementation) {
7
+ this.#apiKey = apiKey;
8
+ let end = baseUrl.length;
9
+ while (end > 0 && baseUrl.charCodeAt(end - 1) === 47)
10
+ end -= 1;
11
+ this.baseUrl = baseUrl.slice(0, end);
12
+ this.#fetch = fetchImplementation;
13
+ }
14
+ async json(method, path, options = {}) {
15
+ const attempts = options.retry === true ? 2 : 1;
16
+ let lastError;
17
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
18
+ try {
19
+ const response = await this.#fetch(`${this.baseUrl}${path}`, {
20
+ method,
21
+ headers: {
22
+ Accept: "application/json",
23
+ ...(options.body === undefined ? {} : { "Content-Type": "application/json" }),
24
+ Authorization: `Bearer ${this.#apiKey}`,
25
+ ...options.headers,
26
+ },
27
+ ...(options.body === undefined ? {} : { body: JSON.stringify(options.body) }),
28
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
29
+ });
30
+ if (!response.ok)
31
+ throw await this.responseError(response);
32
+ if (response.status === 204)
33
+ return undefined;
34
+ return (await response.json());
35
+ }
36
+ catch (error) {
37
+ if (options.signal?.aborted === true || isAbort(error))
38
+ throw abortError(error);
39
+ if (error instanceof AexError)
40
+ throw error;
41
+ lastError = error;
42
+ }
43
+ }
44
+ throw new SessionError("Could not reach the Aex API", { cause: lastError });
45
+ }
46
+ async *events(sessionId, options = {}) {
47
+ let cursor = options.after ?? 0;
48
+ const follow = options.follow ?? true;
49
+ let consecutiveFailures = 0;
50
+ while (true) {
51
+ try {
52
+ const query = new URLSearchParams({ after: String(cursor), follow: String(follow) });
53
+ const response = await this.#fetch(`${this.baseUrl}/v1/sessions/${encodeURIComponent(sessionId)}/events?${query}`, {
54
+ method: "GET",
55
+ headers: {
56
+ Accept: "text/event-stream",
57
+ Authorization: `Bearer ${this.#apiKey}`,
58
+ ...(cursor > 0 ? { "Last-Event-ID": String(cursor) } : {}),
59
+ },
60
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
61
+ });
62
+ if (!response.ok)
63
+ throw await this.responseError(response);
64
+ if (response.body === null)
65
+ throw new SessionError("The Aex event stream had no body");
66
+ let received = false;
67
+ for await (const event of parseEventStream(response.body)) {
68
+ if (event.seq <= cursor)
69
+ continue;
70
+ cursor = event.seq;
71
+ received = true;
72
+ consecutiveFailures = 0;
73
+ yield event;
74
+ }
75
+ if (!follow)
76
+ return;
77
+ if (!received)
78
+ consecutiveFailures += 1;
79
+ }
80
+ catch (error) {
81
+ if (options.signal?.aborted === true || isAbort(error))
82
+ throw abortError(error);
83
+ if (error instanceof AexError && error.status !== undefined && error.status < 500)
84
+ throw error;
85
+ consecutiveFailures += 1;
86
+ if (consecutiveFailures > 5) {
87
+ if (error instanceof AexError)
88
+ throw error;
89
+ throw new SessionError("The Aex event stream disconnected", { cause: error });
90
+ }
91
+ }
92
+ await delay(Math.min(2_000, 100 * 2 ** (consecutiveFailures - 1)), options.signal);
93
+ }
94
+ }
95
+ async responseError(response) {
96
+ let envelope;
97
+ try {
98
+ envelope = (await response.json());
99
+ }
100
+ catch {
101
+ // Fall through to a status-based error.
102
+ }
103
+ if (envelope?.error !== undefined)
104
+ return errorFromApi(envelope.error, response.status);
105
+ return new SessionError(`Aex API request failed with HTTP ${response.status}`, {
106
+ status: response.status,
107
+ requestId: response.headers.get("x-request-id") ?? undefined,
108
+ });
109
+ }
110
+ }
111
+ async function* parseEventStream(stream) {
112
+ const reader = stream.getReader();
113
+ const decoder = new TextDecoder();
114
+ let buffer = "";
115
+ let frame = { data: [] };
116
+ const dispatch = () => {
117
+ if (frame.data.length === 0) {
118
+ frame = { data: [] };
119
+ return undefined;
120
+ }
121
+ const data = frame.data.join("\n");
122
+ frame = { data: [] };
123
+ try {
124
+ return JSON.parse(data);
125
+ }
126
+ catch (cause) {
127
+ throw new SessionError("Aex sent an invalid event", { cause });
128
+ }
129
+ };
130
+ const line = (raw) => {
131
+ const value = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
132
+ if (value === "")
133
+ return dispatch();
134
+ if (value.startsWith(":"))
135
+ return undefined;
136
+ const separator = value.indexOf(":");
137
+ const field = separator === -1 ? value : value.slice(0, separator);
138
+ let content = separator === -1 ? "" : value.slice(separator + 1);
139
+ if (content.startsWith(" "))
140
+ content = content.slice(1);
141
+ if (field === "data")
142
+ frame.data.push(content);
143
+ else if (field === "id")
144
+ frame.id = content;
145
+ else if (field === "event")
146
+ frame.event = content;
147
+ return undefined;
148
+ };
149
+ try {
150
+ while (true) {
151
+ const { done, value } = await reader.read();
152
+ buffer += decoder.decode(value, { stream: !done });
153
+ let newline = buffer.indexOf("\n");
154
+ while (newline !== -1) {
155
+ const event = line(buffer.slice(0, newline));
156
+ buffer = buffer.slice(newline + 1);
157
+ if (event !== undefined)
158
+ yield event;
159
+ newline = buffer.indexOf("\n");
160
+ }
161
+ if (done)
162
+ break;
163
+ }
164
+ if (buffer !== "") {
165
+ const event = line(buffer);
166
+ if (event !== undefined)
167
+ yield event;
168
+ }
169
+ const final = dispatch();
170
+ if (final !== undefined)
171
+ yield final;
172
+ }
173
+ finally {
174
+ reader.releaseLock();
175
+ }
176
+ }
177
+ function isAbort(error) {
178
+ return error instanceof AbortError || (error instanceof DOMException && error.name === "AbortError");
179
+ }
180
+ function delay(milliseconds, signal) {
181
+ if (signal?.aborted === true)
182
+ return Promise.reject(abortError(signal.reason));
183
+ return new Promise((resolve, reject) => {
184
+ const cleanup = () => signal?.removeEventListener("abort", onAbort);
185
+ const timer = setTimeout(() => {
186
+ cleanup();
187
+ resolve();
188
+ }, milliseconds);
189
+ const onAbort = () => {
190
+ clearTimeout(timer);
191
+ cleanup();
192
+ reject(abortError(signal?.reason));
193
+ };
194
+ signal?.addEventListener("abort", onAbort, { once: true });
195
+ });
196
+ }
package/package.json CHANGED
@@ -1,64 +1,22 @@
1
1
  {
2
2
  "name": "@aexhq/sdk",
3
- "version": "0.54.1",
4
- "description": "Zero-dependency TypeScript SDK for the AEX v1 public API.",
5
- "aex": {
6
- "owner": "clients",
7
- "role": "client",
8
- "artifact": "npm_package",
9
- "layers": [
10
- "unit",
11
- "user"
12
- ],
13
- "concerns": [
14
- "contract",
15
- "compatibility",
16
- "property",
17
- "security"
18
- ],
19
- "seams": [
20
- "npm.registry.publish"
21
- ],
22
- "security_tier": "public_edge",
23
- "risk": [
24
- "generated_code"
25
- ],
26
- "scenarios": ["packed.sdk-install-node", "packed.sdk-install-bun"],
27
- "targets": {
28
- "conformance": "unit",
29
- "security": "unit",
30
- "compatibility": "unit",
31
- "packed_user": "user"
32
- },
33
- "not_applicable": {
34
- "live_suite": "clean-install and packed-tarball evidence is package-owned; the SDK has no deployed endpoint"
35
- }
36
- },
3
+ "version": "0.55.1",
4
+ "description": "TypeScript SDK for Aex sessions",
37
5
  "license": "Apache-2.0",
38
- "keywords": [
39
- "aex",
40
- "agent",
41
- "sdk",
42
- "autonomous-agents",
43
- "agent-runtime",
44
- "typescript"
45
- ],
46
6
  "homepage": "https://aex.dev",
47
7
  "repository": {
48
8
  "type": "git",
49
9
  "url": "git+https://github.com/aexhq/aex.git",
50
10
  "directory": "packages/sdk"
51
11
  },
52
- "bugs": {
53
- "url": "https://github.com/aexhq/aex/issues"
12
+ "type": "module",
13
+ "engines": {
14
+ "node": ">=22.0.0"
54
15
  },
55
16
  "publishConfig": {
56
17
  "access": "public",
57
18
  "provenance": true
58
19
  },
59
- "type": "module",
60
- "main": "./dist/index.js",
61
- "types": "./dist/index.d.ts",
62
20
  "exports": {
63
21
  ".": {
64
22
  "types": "./dist/index.d.ts",
@@ -68,26 +26,20 @@
68
26
  },
69
27
  "files": [
70
28
  "dist",
71
- "README.md",
72
- "LICENSE",
73
- "NOTICE"
29
+ "README.md"
74
30
  ],
75
31
  "scripts": {
76
- "build": "tsc -p tsconfig.build.json",
77
- "lint": "tsc --noEmit",
78
- "typecheck": "tsc --noEmit",
79
- "test": "bun run test:unit",
80
- "test:unit": "bun test --isolate test/unit",
81
- "test:coverage": "bun test --isolate --coverage test/unit",
82
- "prepack": "bun run build",
83
- "pack:dry-run": "bun pm pack --dry-run --ignore-scripts"
32
+ "build": "tsc -p tsconfig.json",
33
+ "test": "tsc -p tsconfig.json && node --test"
84
34
  },
85
- "dependencies": {},
86
- "devDependencies": {
87
- "@types/bun": "1.3.14"
35
+ "dependencies": {
36
+ "@aexhq/contracts": "0.26.1"
88
37
  },
89
- "engines": {
90
- "node": ">=22.0.0",
91
- "bun": ">=1.3.14"
38
+ "peerDependencies": {
39
+ "zod": "^4.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "typescript": "^5.9.2",
43
+ "zod": "^4.0.0"
92
44
  }
93
45
  }