nanocodex 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/internal.mjs ADDED
@@ -0,0 +1,303 @@
1
+ const AGENT_STATE = Symbol("nanocodex.agent");
2
+ const TURN_STATE = Symbol("nanocodex.turn");
3
+ const hostSessions = new Map();
4
+ const hostConnections = new Map();
5
+ let activeHost;
6
+ let nextHostConnection = 1;
7
+ let nextAgentUid = 1;
8
+
9
+ export function defineRuntime(definition) {
10
+ if (!definition || typeof definition.create !== "function") {
11
+ throw new TypeError("a Nanocodex runtime must define create(options)");
12
+ }
13
+ return Object.freeze({
14
+ key: definition.key ?? "custom",
15
+ name: definition.name ?? "Nanocodex Agent",
16
+ type: definition.type ?? "custom",
17
+ create: definition.create,
18
+ dispose: definition.dispose || ((agent) => agent.free()),
19
+ subscribe: definition.subscribe,
20
+ adopt: definition.adopt,
21
+ release: definition.release,
22
+ decorate: definition.decorate,
23
+ });
24
+ }
25
+
26
+ export async function createAgentClient(runtime, options = {}) {
27
+ if (!runtime || typeof runtime.create !== "function") {
28
+ throw new TypeError("createAgent requires a Nanocodex runtime");
29
+ }
30
+ return createAgent(await runtime.create(options), runtime);
31
+ }
32
+
33
+ export function prompt(agent, options) {
34
+ const state = agentState(agent);
35
+ const input = actionInput(options);
36
+ const raw = typeof input === "string"
37
+ ? state.raw.prompt(input)
38
+ : state.raw.promptContent(JSON.stringify(input));
39
+ return createTurn(raw, agent);
40
+ }
41
+
42
+ export function getTurnResult(turn) {
43
+ const state = turnState(turn);
44
+ state.result ||= Promise.resolve().then(() => state.raw.result());
45
+ return state.result;
46
+ }
47
+
48
+ export function steer(turn, options) {
49
+ const state = turnState(turn);
50
+ const input = actionInput(options);
51
+ return typeof input === "string"
52
+ ? state.raw.steer(input)
53
+ : state.raw.steerContent(JSON.stringify(input));
54
+ }
55
+
56
+ export function cancel(turn) {
57
+ return turnState(turn).raw.cancel();
58
+ }
59
+
60
+ export async function fork(agent, options) {
61
+ const state = agentState(agent);
62
+ const at = options?.at;
63
+ const raw = at === undefined
64
+ ? await state.raw.fork()
65
+ : await state.raw.forkFrom(turnState(at).raw);
66
+ return createAgent(raw, state.runtime);
67
+ }
68
+
69
+ export async function spawn(agent) {
70
+ const state = agentState(agent);
71
+ return createAgent(await state.raw.spawn(), state.runtime);
72
+ }
73
+
74
+ export function subscribeAgentEvents(agent, listener, options = {}) {
75
+ const state = agentState(agent);
76
+ if (typeof state.runtime.subscribe !== "function") {
77
+ throw new Error("this Nanocodex runtime does not expose agent events");
78
+ }
79
+ if (typeof listener !== "function") {
80
+ throw new TypeError("watchAgentEvents requires a listener");
81
+ }
82
+ return state.runtime.subscribe((event) => {
83
+ if (options.includeAllSessions || !event?.request_id || event.request_id === agent.sessionId) {
84
+ listener(event);
85
+ }
86
+ });
87
+ }
88
+
89
+ export function toWasmConfig(options = {}) {
90
+ const apiKey = options.apiKey;
91
+ if (typeof apiKey !== "string" || !apiKey.trim()) {
92
+ throw new TypeError("apiKey must be a non-empty string");
93
+ }
94
+ const config = { api_key: apiKey };
95
+ copy(config, "thinking", options.thinking);
96
+ copy(config, "reasoning_mode", options.reasoningMode);
97
+ copy(config, "websocket_url", options.websocketUrl);
98
+ copy(config, "api_base_url", options.apiBaseUrl);
99
+ copy(config, "instructions", options.instructions);
100
+ copy(config, "session_id", options.sessionId);
101
+ return config;
102
+ }
103
+
104
+ export function createEventChannel() {
105
+ const listeners = new Set();
106
+ return Object.freeze({
107
+ emit(eventJson) {
108
+ const event = typeof eventJson === "string" ? JSON.parse(eventJson) : eventJson;
109
+ for (const listener of listeners) listener(event);
110
+ },
111
+ subscribe(listener) {
112
+ listeners.add(listener);
113
+ return () => listeners.delete(listener);
114
+ },
115
+ });
116
+ }
117
+
118
+ export function activateHost(host) {
119
+ if (!host || typeof host.connect !== "function") {
120
+ throw new TypeError("a Nanocodex host must define connect()");
121
+ }
122
+ activeHost = host;
123
+ globalThis.nanocodexHost = hostBridge;
124
+ }
125
+
126
+ export function bindHostSession(host, sessionId) {
127
+ const existing = hostSessions.get(sessionId);
128
+ if (existing && existing !== host) {
129
+ throw new Error(`Nanocodex session ID is already active: ${sessionId}`);
130
+ }
131
+ hostSessions.set(sessionId, host);
132
+ }
133
+
134
+ export function releaseHostSession(host, sessionId) {
135
+ if (hostSessions.get(sessionId) === host) hostSessions.delete(sessionId);
136
+ }
137
+
138
+ const hostBridge = Object.freeze({
139
+ async connect(endpoint, apiKey, sessionId) {
140
+ const host = requiredSessionHost(sessionId);
141
+ const result = JSON.parse(await host.connect(endpoint, apiKey, sessionId));
142
+ const handle = nextHostConnection++;
143
+ hostConnections.set(handle, { host, handle: result.handle });
144
+ hostSessions.set(sessionId, host);
145
+ return JSON.stringify({ ...result, handle });
146
+ },
147
+ send(handle, message) {
148
+ const connection = hostConnections.get(handle);
149
+ return connection
150
+ ? connection.host.send(connection.handle, message)
151
+ : Promise.resolve(JSON.stringify({ ok: false, reconnectable: true, error: "unknown WebSocket handle" }));
152
+ },
153
+ next(handle, timeoutMs) {
154
+ const connection = hostConnections.get(handle);
155
+ return connection
156
+ ? connection.host.next(connection.handle, timeoutMs)
157
+ : Promise.resolve(JSON.stringify({ kind: "closed", detail: "for an unknown WebSocket handle" }));
158
+ },
159
+ close(handle) {
160
+ const connection = hostConnections.get(handle);
161
+ if (!connection) return;
162
+ hostConnections.delete(handle);
163
+ connection.host.close(connection.handle);
164
+ },
165
+ sleep(milliseconds) {
166
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
167
+ },
168
+ executeCode(source, sessionId, callId) {
169
+ return requiredSessionHost(sessionId).executeCode(source, sessionId, callId);
170
+ },
171
+ toolDefinitions(sessionId) {
172
+ // ModelRun builds its stable tool prefix inside the WASM constructor,
173
+ // immediately before the returned session can be adopted. Runtime
174
+ // factories activate their host directly around that synchronous step.
175
+ return (hostSessions.get(sessionId) ?? requiredActiveHost()).toolDefinitions();
176
+ },
177
+ emitEvent(eventJson) {
178
+ const event = JSON.parse(eventJson);
179
+ requiredSessionHost(event.request_id).emitEvent(eventJson);
180
+ },
181
+ });
182
+
183
+ function createAgent(raw, runtime) {
184
+ if (!raw || typeof raw.prompt !== "function") {
185
+ throw new TypeError("the runtime returned an invalid Nanocodex agent handle");
186
+ }
187
+ const state = {
188
+ raw,
189
+ runtime,
190
+ disposed: false,
191
+ sessionId: raw.sessionId,
192
+ uid: `agent-${nextAgentUid++}`,
193
+ };
194
+ try {
195
+ runtime.adopt?.(raw);
196
+ } catch (error) {
197
+ runtime.dispose(raw);
198
+ throw error;
199
+ }
200
+ const agent = agentView(state, {});
201
+ return runtime.decorate ? runtime.decorate(agent) : agent;
202
+ }
203
+
204
+ function agentView(state, extensions) {
205
+ let agent;
206
+ const base = {
207
+ uid: state.uid,
208
+ key: state.runtime.key,
209
+ name: state.runtime.name,
210
+ type: state.runtime.type,
211
+ get sessionId() { return state.sessionId; },
212
+ extend(fn) {
213
+ if (typeof fn !== "function") throw new TypeError("agent.extend requires a decorator function");
214
+ const value = fn(agent);
215
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
216
+ throw new TypeError("an agent decorator must return an object");
217
+ }
218
+ const extension = { ...value };
219
+ for (const key of Object.keys(base)) delete extension[key];
220
+ return agentView(state, deepMerge(extensions, extension));
221
+ },
222
+ dispose() {
223
+ if (state.disposed) return;
224
+ state.disposed = true;
225
+ state.runtime.release?.(state.raw);
226
+ state.runtime.dispose(state.raw);
227
+ },
228
+ };
229
+ agent = Object.assign(base, extensions);
230
+ Object.defineProperty(agent, AGENT_STATE, { value: state });
231
+ return agent;
232
+ }
233
+
234
+ function requiredSessionHost(sessionId) {
235
+ const host = hostSessions.get(sessionId);
236
+ if (!host) throw new Error(`no Nanocodex host is active for session: ${sessionId}`);
237
+ return host;
238
+ }
239
+
240
+ function requiredActiveHost() {
241
+ if (!activeHost) throw new Error("no Nanocodex host is active");
242
+ return activeHost;
243
+ }
244
+
245
+ function createTurn(raw, agent) {
246
+ if (!raw || typeof raw.result !== "function") {
247
+ throw new TypeError("the runtime returned an invalid Nanocodex turn handle");
248
+ }
249
+ const state = { raw, agent, result: undefined, disposed: false };
250
+ const turn = {
251
+ get agent() { return state.agent; },
252
+ result: () => getTurnResult(turn),
253
+ steer: (input) => steer(turn, input),
254
+ cancel: () => cancel(turn),
255
+ dispose() {
256
+ if (state.disposed) return;
257
+ state.disposed = true;
258
+ state.raw.free();
259
+ },
260
+ };
261
+ Object.defineProperty(turn, TURN_STATE, { value: state });
262
+ return Object.freeze(turn);
263
+ }
264
+
265
+ function agentState(agent) {
266
+ const state = agent?.[AGENT_STATE];
267
+ if (!state) throw new TypeError("expected a Nanocodex agent");
268
+ if (state.disposed) throw new Error("the Nanocodex agent has been disposed");
269
+ return state;
270
+ }
271
+
272
+ function turnState(turn) {
273
+ const state = turn?.[TURN_STATE];
274
+ if (!state) throw new TypeError("expected a Nanocodex turn");
275
+ if (state.disposed) throw new Error("the Nanocodex turn has been disposed");
276
+ return state;
277
+ }
278
+
279
+ function actionInput(options) {
280
+ const input = options?.input;
281
+ if (typeof input !== "string" && !Array.isArray(input)) {
282
+ throw new TypeError("turn input must be a string or ordered content array");
283
+ }
284
+ return input;
285
+ }
286
+
287
+ function deepMerge(left, right) {
288
+ const merged = { ...left };
289
+ for (const [key, value] of Object.entries(right)) {
290
+ merged[key] = isObject(merged[key]) && isObject(value)
291
+ ? deepMerge(merged[key], value)
292
+ : value;
293
+ }
294
+ return merged;
295
+ }
296
+
297
+ function isObject(value) {
298
+ return value !== null && typeof value === "object" && !Array.isArray(value);
299
+ }
300
+
301
+ function copy(target, key, value) {
302
+ if (value !== undefined) target[key] = value;
303
+ }
@@ -0,0 +1,24 @@
1
+ import type {
2
+ AgentOptions,
3
+ DefaultAgent,
4
+ ToolMap,
5
+ } from "../types.mjs";
6
+
7
+ export type Agent = DefaultAgent;
8
+
9
+ /** Creates a Node-hosted Rust/WASM Agent. */
10
+ export function create(options: create.Options): Promise<create.ReturnType>;
11
+ export declare namespace create {
12
+ type Options = AgentOptions & {
13
+ apiBaseUrl?: string | undefined;
14
+ apiKey: string;
15
+ connectTimeoutMs?: number | undefined;
16
+ maxFrameBytes?: number | undefined;
17
+ maxQueuedBytes?: number | undefined;
18
+ maxQueuedMessages?: number | undefined;
19
+ sendTimeoutMs?: number | undefined;
20
+ tools?: ToolMap | undefined;
21
+ websocketUrl?: string | undefined;
22
+ };
23
+ type ReturnType = Agent;
24
+ }
package/node/Agent.mjs ADDED
@@ -0,0 +1,51 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ import { agentActions } from "../actions/index.mjs";
4
+ import {
5
+ activateHost,
6
+ bindHostSession,
7
+ createAgentClient,
8
+ createEventChannel,
9
+ defineRuntime,
10
+ releaseHostSession,
11
+ toWasmConfig,
12
+ } from "../internal.mjs";
13
+ import { createNodeHost } from "./host.mjs";
14
+
15
+ const require = createRequire(import.meta.url);
16
+ const { Nanocodex } = require("../pkg-node/nanocodex.js");
17
+
18
+ export function create(options = {}) {
19
+ const {
20
+ thinking,
21
+ reasoningMode,
22
+ instructions,
23
+ sessionId,
24
+ apiKey,
25
+ websocketUrl,
26
+ apiBaseUrl,
27
+ ...hostOptions
28
+ } = options;
29
+ const events = createEventChannel();
30
+ const host = createNodeHost({ ...hostOptions, onEvent: events.emit });
31
+ activateHost(host);
32
+ const runtime = defineRuntime({
33
+ key: "node-wasm",
34
+ name: "Nanocodex Node WASM",
35
+ type: "node",
36
+ create(config) {
37
+ activateHost(host);
38
+ return new Nanocodex(JSON.stringify(toWasmConfig({
39
+ apiKey,
40
+ websocketUrl,
41
+ apiBaseUrl,
42
+ ...config,
43
+ })));
44
+ },
45
+ subscribe: events.subscribe,
46
+ adopt: (raw) => bindHostSession(host, raw.sessionId),
47
+ release: (raw) => releaseHostSession(host, raw.sessionId),
48
+ decorate: (agent) => agent.extend(agentActions()),
49
+ });
50
+ return createAgentClient(runtime, { thinking, reasoningMode, instructions, sessionId });
51
+ }
package/node/host.mjs ADDED
@@ -0,0 +1,204 @@
1
+ import { Console } from "node:console";
2
+ import { createRequire } from "node:module";
3
+ import WebSocket from "ws";
4
+
5
+ import { createCodeRuntime } from "../runtime/code-runtime.mjs";
6
+
7
+ const RESPONSES_WEBSOCKETS_BETA = "responses_websockets=2026-02-06";
8
+ const DEFAULT_MAX_QUEUED_MESSAGES = 4_096;
9
+ const DEFAULT_MAX_QUEUED_BYTES = 32 * 1024 * 1024;
10
+ const DEFAULT_MAX_FRAME_BYTES = 16 * 1024 * 1024;
11
+
12
+ export function createNodeHost(options = {}) {
13
+ const connections = new Map();
14
+ const code = createCodeRuntime(options.tools, {
15
+ require: createRequire(`${process.cwd()}/`),
16
+ console: new Console({ stdout: process.stderr, stderr: process.stderr }),
17
+ });
18
+ const onEvent = options.onEvent || (() => {});
19
+ const connectTimeoutMs = options.connectTimeoutMs ?? 30_000;
20
+ const sendTimeoutMs = options.sendTimeoutMs ?? 30_000;
21
+ const maxQueuedMessages = options.maxQueuedMessages ?? DEFAULT_MAX_QUEUED_MESSAGES;
22
+ const maxQueuedBytes = options.maxQueuedBytes ?? DEFAULT_MAX_QUEUED_BYTES;
23
+ const maxFrameBytes = options.maxFrameBytes ?? DEFAULT_MAX_FRAME_BYTES;
24
+ let nextHandle = 1;
25
+
26
+ function connect(endpoint, apiKey, sessionId) {
27
+ return new Promise((resolve, reject) => {
28
+ let settled = false;
29
+ let upgradeResponse;
30
+ const socket = new WebSocket(endpoint, {
31
+ handshakeTimeout: connectTimeoutMs,
32
+ maxPayload: maxFrameBytes,
33
+ headers: {
34
+ Authorization: `Bearer ${apiKey}`,
35
+ "OpenAI-Beta": RESPONSES_WEBSOCKETS_BETA,
36
+ "x-openai-internal-codex-responses-lite": "true",
37
+ "session-id": sessionId,
38
+ "thread-id": sessionId,
39
+ "x-client-request-id": sessionId,
40
+ "x-responsesapi-include-timing-metrics": "true",
41
+ "User-Agent": "nanocodex-wasm/0.1.0",
42
+ },
43
+ });
44
+ const handle = nextHandle++;
45
+ const connection = queueState(socket);
46
+
47
+ socket.on("upgrade", (response) => { upgradeResponse = response; });
48
+ socket.on("open", () => {
49
+ settled = true;
50
+ connections.set(handle, connection);
51
+ const headers = upgradeResponse?.headers || {};
52
+ resolve(JSON.stringify({
53
+ handle,
54
+ status: upgradeResponse?.statusCode || 101,
55
+ request_id: header(headers, "x-request-id"),
56
+ server_model: header(headers, "openai-model"),
57
+ reasoning_included: header(headers, "x-reasoning-included") !== undefined,
58
+ turn_state: header(headers, "x-codex-turn-state"),
59
+ }));
60
+ });
61
+ socket.on("message", (data, isBinary) => {
62
+ enqueue(connection, isBinary
63
+ ? { kind: "binary" }
64
+ : { kind: "text", text: data.toString("utf8") });
65
+ });
66
+ socket.on("close", (status, reason) => {
67
+ if (!connection.intentionallyClosed && !connection.overflowed) {
68
+ const suffix = reason.length ? `: ${reason.toString("utf8")}` : "";
69
+ enqueue(connection, { kind: "closed", detail: `with code ${status}${suffix}` });
70
+ }
71
+ });
72
+ socket.on("error", (error) => {
73
+ if (!settled) {
74
+ settled = true;
75
+ reject(error);
76
+ } else {
77
+ enqueue(connection, { kind: "error", detail: errorMessage(error) });
78
+ }
79
+ });
80
+ });
81
+ }
82
+
83
+ function send(handle, message) {
84
+ const connection = connections.get(handle);
85
+ if (!connection || connection.socket.readyState !== WebSocket.OPEN) {
86
+ return Promise.resolve(JSON.stringify({
87
+ ok: false,
88
+ reconnectable: true,
89
+ error: "WebSocket is no longer open",
90
+ }));
91
+ }
92
+ return new Promise((resolve) => {
93
+ let completed = false;
94
+ const timer = setTimeout(() => finish({
95
+ ok: false,
96
+ reconnectable: false,
97
+ error: `sending a WebSocket frame exceeded ${sendTimeoutMs} milliseconds`,
98
+ }), sendTimeoutMs);
99
+ function finish(result) {
100
+ if (completed) return;
101
+ completed = true;
102
+ clearTimeout(timer);
103
+ resolve(JSON.stringify(result));
104
+ }
105
+ connection.socket.send(message, (error) => finish(error ? {
106
+ ok: false,
107
+ reconnectable: connection.socket.readyState !== WebSocket.OPEN,
108
+ error: errorMessage(error),
109
+ } : { ok: true }));
110
+ });
111
+ }
112
+
113
+ function next(handle, timeoutMs) {
114
+ const connection = connections.get(handle);
115
+ if (!connection) {
116
+ return Promise.resolve(JSON.stringify({ kind: "closed", detail: "before the next frame" }));
117
+ }
118
+ if (connection.queue.length) {
119
+ const entry = connection.queue.shift();
120
+ connection.queuedBytes -= entry.bytes;
121
+ return Promise.resolve(JSON.stringify(entry.message));
122
+ }
123
+ if (connection.waiter) return Promise.reject(new Error("concurrent reads are unsupported"));
124
+ return new Promise((resolve) => {
125
+ const timer = setTimeout(() => {
126
+ connection.waiter = undefined;
127
+ resolve(JSON.stringify({ kind: "timeout" }));
128
+ }, timeoutMs);
129
+ connection.waiter = (message) => {
130
+ clearTimeout(timer);
131
+ connection.waiter = undefined;
132
+ resolve(JSON.stringify(message));
133
+ };
134
+ });
135
+ }
136
+
137
+ function close(handle) {
138
+ const connection = connections.get(handle);
139
+ if (!connection) return;
140
+ connections.delete(handle);
141
+ connection.intentionallyClosed = true;
142
+ connection.waiter?.({ kind: "closed", detail: "by the WASM runtime" });
143
+ connection.socket.close();
144
+ }
145
+
146
+ function enqueue(connection, message) {
147
+ if (connection.overflowed) return;
148
+ if (connection.waiter) {
149
+ connection.waiter(message);
150
+ return;
151
+ }
152
+ const bytes = messageBytes(message);
153
+ if (connection.queue.length >= maxQueuedMessages || connection.queuedBytes + bytes > maxQueuedBytes) {
154
+ connection.queue.length = 0;
155
+ connection.queuedBytes = 0;
156
+ connection.overflowed = true;
157
+ const error = {
158
+ kind: "error",
159
+ detail: `receive queue exceeded ${maxQueuedMessages} messages or ${maxQueuedBytes} bytes`,
160
+ };
161
+ connection.queue.push({ message: error, bytes: messageBytes(error) });
162
+ connection.socket.terminate();
163
+ return;
164
+ }
165
+ connection.queue.push({ message, bytes });
166
+ connection.queuedBytes += bytes;
167
+ }
168
+
169
+ return Object.freeze({
170
+ connect,
171
+ send,
172
+ next,
173
+ close,
174
+ sleep: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
175
+ executeCode: code.executeCode,
176
+ toolDefinitions: code.toolDefinitions,
177
+ emitEvent: onEvent,
178
+ reset: code.reset,
179
+ });
180
+ }
181
+
182
+ function queueState(socket) {
183
+ return {
184
+ socket,
185
+ queue: [],
186
+ queuedBytes: 0,
187
+ waiter: undefined,
188
+ intentionallyClosed: false,
189
+ overflowed: false,
190
+ };
191
+ }
192
+
193
+ function header(headers, name) {
194
+ const value = headers[name];
195
+ return Array.isArray(value) ? value[0] : value;
196
+ }
197
+
198
+ function messageBytes(message) {
199
+ return Buffer.byteLength(message.kind === "text" ? message.text : JSON.stringify(message), "utf8");
200
+ }
201
+
202
+ function errorMessage(error) {
203
+ return error && (error.stack || error.message) || String(error);
204
+ }
@@ -0,0 +1,13 @@
1
+ export { Actions } from "../index.mjs";
2
+ export type {
3
+ AgentEvent,
4
+ PromptInput,
5
+ PromptItem,
6
+ ReasoningMode,
7
+ Thinking,
8
+ Tool,
9
+ ToolContext,
10
+ ToolMap,
11
+ Turn,
12
+ } from "../types.mjs";
13
+ export * as Agent from "./Agent.mjs";
package/node/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export { Actions } from "../index.mjs";
2
+ export * as Agent from "./Agent.mjs";
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "nanocodex",
3
+ "version": "0.1.1",
4
+ "description": "Viem-style Node and browser bindings for the Nanocodex WASM agent",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./index.d.mts",
10
+ "import": "./index.mjs"
11
+ },
12
+ "./node": {
13
+ "types": "./node/index.d.mts",
14
+ "import": "./node/index.mjs"
15
+ },
16
+ "./browser": {
17
+ "types": "./browser/index.d.mts",
18
+ "import": "./browser/index.mjs"
19
+ }
20
+ },
21
+ "files": [
22
+ "actions",
23
+ "browser",
24
+ "node",
25
+ "pkg-node",
26
+ "pkg-web",
27
+ "runtime",
28
+ "scripts/check-package.mjs",
29
+ "internal.mjs",
30
+ "index.d.mts",
31
+ "index.mjs",
32
+ "types.d.mts",
33
+ "README.md"
34
+ ],
35
+ "publishConfig": {
36
+ "access": "public",
37
+ "provenance": true
38
+ },
39
+ "scripts": {
40
+ "check:package": "node scripts/check-package.mjs",
41
+ "prepack": "npm run check:package",
42
+ "test": "node --test test/*.test.mjs && npm run test:typecheck && npm run check:package",
43
+ "test:typecheck": "tsc -p test/tsconfig.json"
44
+ },
45
+ "dependencies": {
46
+ "ws": "^8.18.3"
47
+ },
48
+ "devDependencies": {
49
+ "pkg-pr-new": "0.0.79",
50
+ "typescript": "5.9.3"
51
+ },
52
+ "engines": {
53
+ "node": ">=22.13.0"
54
+ },
55
+ "license": "MIT OR Apache-2.0",
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "git+https://github.com/gakonst/nanocodex.git",
59
+ "directory": "js/bindings"
60
+ }
61
+ }