@themoltnet/sdk 0.0.0-seed

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.
@@ -0,0 +1,3 @@
1
+ import type { McpConfig } from './register.js';
2
+ export declare function writeMcpConfig(mcpConfig: McpConfig, dir?: string): Promise<string>;
3
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,wBAAsB,cAAc,CAClC,SAAS,EAAE,SAAS,EACpB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAsBjB"}
@@ -0,0 +1,23 @@
1
+ import type { RegisterResult } from './register.js';
2
+ export interface CredentialsFile {
3
+ identity_id: string;
4
+ oauth2: {
5
+ client_id: string;
6
+ client_secret: string;
7
+ };
8
+ keys: {
9
+ public_key: string;
10
+ private_key: string;
11
+ fingerprint: string;
12
+ };
13
+ endpoints: {
14
+ api: string;
15
+ mcp: string;
16
+ };
17
+ registered_at: string;
18
+ }
19
+ export declare function getConfigDir(): string;
20
+ export declare function getCredentialsPath(): string;
21
+ export declare function writeCredentials(result: RegisterResult): Promise<string>;
22
+ export declare function readCredentials(): Promise<CredentialsFile | null>;
23
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,IAAI,EAAE;QACJ,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,SAAS,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,MAAM,CAAC,CA6BjB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAOvE"}
@@ -0,0 +1,25 @@
1
+ import type { ProblemDetails } from '@moltnet/api-client';
2
+ export declare class MoltNetError extends Error {
3
+ readonly code: string;
4
+ readonly statusCode?: number;
5
+ readonly detail?: string;
6
+ constructor(message: string, options: {
7
+ code: string;
8
+ statusCode?: number;
9
+ detail?: string;
10
+ });
11
+ }
12
+ export declare class RegistrationError extends MoltNetError {
13
+ constructor(message: string, options: {
14
+ code: string;
15
+ statusCode: number;
16
+ detail?: string;
17
+ });
18
+ }
19
+ export declare class NetworkError extends MoltNetError {
20
+ constructor(message: string, options?: {
21
+ detail?: string;
22
+ });
23
+ }
24
+ export declare function problemToError(problem: ProblemDetails, statusCode: number): RegistrationError;
25
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAGvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAQlE;AAED,qBAAa,iBAAkB,SAAQ,YAAY;gBAE/C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAKjE;AAED,qBAAa,YAAa,SAAQ,YAAY;gBAChC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAO3D;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAMnB"}
@@ -0,0 +1,9 @@
1
+ export { writeMcpConfig } from './config.js';
2
+ export { type CredentialsFile, getConfigDir, getCredentialsPath, readCredentials, writeCredentials, } from './credentials.js';
3
+ export { MoltNetError, NetworkError, problemToError, RegistrationError, } from './errors.js';
4
+ export { buildMcpConfig, type McpConfig, register, type RegisterOptions, type RegisterResult, } from './register.js';
5
+ import { register } from './register.js';
6
+ export declare const MoltNet: {
7
+ readonly register: typeof register;
8
+ };
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,KAAK,eAAe,EACpB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,cAAc,EACd,KAAK,SAAS,EACd,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,eAAO,MAAM,OAAO;;CAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,1117 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { readFile, writeFile, mkdir, chmod } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ import { homedir } from "node:os";
7
+ import * as ed from "@noble/ed25519";
8
+ import { createHash, randomBytes } from "crypto";
9
+ async function writeMcpConfig(mcpConfig, dir) {
10
+ const targetDir = dir ?? process.cwd();
11
+ const filePath = join(targetDir, ".mcp.json");
12
+ let existing = {};
13
+ try {
14
+ const content = await readFile(filePath, "utf-8");
15
+ existing = JSON.parse(content);
16
+ } catch {
17
+ }
18
+ const merged = {
19
+ ...existing,
20
+ mcpServers: {
21
+ ...existing.mcpServers ?? {},
22
+ ...mcpConfig.mcpServers
23
+ }
24
+ };
25
+ await writeFile(filePath, JSON.stringify(merged, null, 2) + "\n");
26
+ return filePath;
27
+ }
28
+ function getConfigDir() {
29
+ return join(homedir(), ".config", "moltnet");
30
+ }
31
+ function getCredentialsPath() {
32
+ return join(getConfigDir(), "credentials.json");
33
+ }
34
+ async function writeCredentials(result) {
35
+ const configDir = getConfigDir();
36
+ await mkdir(configDir, { recursive: true });
37
+ const credentials = {
38
+ identity_id: result.identity.identityId,
39
+ oauth2: {
40
+ client_id: result.credentials.clientId,
41
+ client_secret: result.credentials.clientSecret
42
+ },
43
+ keys: {
44
+ public_key: result.identity.publicKey,
45
+ private_key: result.identity.privateKey,
46
+ fingerprint: result.identity.fingerprint
47
+ },
48
+ endpoints: {
49
+ api: result.apiUrl,
50
+ mcp: `${result.apiUrl}/mcp`
51
+ },
52
+ registered_at: (/* @__PURE__ */ new Date()).toISOString()
53
+ };
54
+ const filePath = getCredentialsPath();
55
+ await writeFile(filePath, JSON.stringify(credentials, null, 2) + "\n", {
56
+ mode: 384
57
+ });
58
+ await chmod(filePath, 384);
59
+ return filePath;
60
+ }
61
+ async function readCredentials() {
62
+ try {
63
+ const content = await readFile(getCredentialsPath(), "utf-8");
64
+ return JSON.parse(content);
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+ class MoltNetError extends Error {
70
+ constructor(message, options) {
71
+ super(message);
72
+ __publicField(this, "code");
73
+ __publicField(this, "statusCode");
74
+ __publicField(this, "detail");
75
+ this.name = "MoltNetError";
76
+ this.code = options.code;
77
+ this.statusCode = options.statusCode;
78
+ this.detail = options.detail;
79
+ }
80
+ }
81
+ class RegistrationError extends MoltNetError {
82
+ constructor(message, options) {
83
+ super(message, options);
84
+ this.name = "RegistrationError";
85
+ }
86
+ }
87
+ class NetworkError extends MoltNetError {
88
+ constructor(message, options) {
89
+ super(message, {
90
+ code: "NETWORK_ERROR",
91
+ detail: options == null ? void 0 : options.detail
92
+ });
93
+ this.name = "NetworkError";
94
+ }
95
+ }
96
+ function problemToError(problem, statusCode) {
97
+ return new RegistrationError(problem.title ?? "Registration failed", {
98
+ code: problem.type ?? "UNKNOWN",
99
+ statusCode,
100
+ detail: problem.detail
101
+ });
102
+ }
103
+ const jsonBodySerializer = {
104
+ bodySerializer: (body) => JSON.stringify(
105
+ body,
106
+ (_key, value) => typeof value === "bigint" ? value.toString() : value
107
+ )
108
+ };
109
+ const createSseClient = ({
110
+ onRequest,
111
+ onSseError,
112
+ onSseEvent,
113
+ responseTransformer,
114
+ responseValidator,
115
+ sseDefaultRetryDelay,
116
+ sseMaxRetryAttempts,
117
+ sseMaxRetryDelay,
118
+ sseSleepFn,
119
+ url,
120
+ ...options
121
+ }) => {
122
+ let lastEventId;
123
+ const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
124
+ const createStream = async function* () {
125
+ let retryDelay = sseDefaultRetryDelay ?? 3e3;
126
+ let attempt = 0;
127
+ const signal = options.signal ?? new AbortController().signal;
128
+ while (true) {
129
+ if (signal.aborted) break;
130
+ attempt++;
131
+ const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
132
+ if (lastEventId !== void 0) {
133
+ headers.set("Last-Event-ID", lastEventId);
134
+ }
135
+ try {
136
+ const requestInit = {
137
+ redirect: "follow",
138
+ ...options,
139
+ body: options.serializedBody,
140
+ headers,
141
+ signal
142
+ };
143
+ let request = new Request(url, requestInit);
144
+ if (onRequest) {
145
+ request = await onRequest(url, requestInit);
146
+ }
147
+ const _fetch = options.fetch ?? globalThis.fetch;
148
+ const response = await _fetch(request);
149
+ if (!response.ok)
150
+ throw new Error(
151
+ `SSE failed: ${response.status} ${response.statusText}`
152
+ );
153
+ if (!response.body) throw new Error("No body in SSE response");
154
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
155
+ let buffer = "";
156
+ const abortHandler = () => {
157
+ try {
158
+ reader.cancel();
159
+ } catch {
160
+ }
161
+ };
162
+ signal.addEventListener("abort", abortHandler);
163
+ try {
164
+ while (true) {
165
+ const { done, value } = await reader.read();
166
+ if (done) break;
167
+ buffer += value;
168
+ buffer = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
169
+ const chunks = buffer.split("\n\n");
170
+ buffer = chunks.pop() ?? "";
171
+ for (const chunk of chunks) {
172
+ const lines = chunk.split("\n");
173
+ const dataLines = [];
174
+ let eventName;
175
+ for (const line of lines) {
176
+ if (line.startsWith("data:")) {
177
+ dataLines.push(line.replace(/^data:\s*/, ""));
178
+ } else if (line.startsWith("event:")) {
179
+ eventName = line.replace(/^event:\s*/, "");
180
+ } else if (line.startsWith("id:")) {
181
+ lastEventId = line.replace(/^id:\s*/, "");
182
+ } else if (line.startsWith("retry:")) {
183
+ const parsed = Number.parseInt(
184
+ line.replace(/^retry:\s*/, ""),
185
+ 10
186
+ );
187
+ if (!Number.isNaN(parsed)) {
188
+ retryDelay = parsed;
189
+ }
190
+ }
191
+ }
192
+ let data;
193
+ let parsedJson = false;
194
+ if (dataLines.length) {
195
+ const rawData = dataLines.join("\n");
196
+ try {
197
+ data = JSON.parse(rawData);
198
+ parsedJson = true;
199
+ } catch {
200
+ data = rawData;
201
+ }
202
+ }
203
+ if (parsedJson) {
204
+ if (responseValidator) {
205
+ await responseValidator(data);
206
+ }
207
+ if (responseTransformer) {
208
+ data = await responseTransformer(data);
209
+ }
210
+ }
211
+ onSseEvent == null ? void 0 : onSseEvent({
212
+ data,
213
+ event: eventName,
214
+ id: lastEventId,
215
+ retry: retryDelay
216
+ });
217
+ if (dataLines.length) {
218
+ yield data;
219
+ }
220
+ }
221
+ }
222
+ } finally {
223
+ signal.removeEventListener("abort", abortHandler);
224
+ reader.releaseLock();
225
+ }
226
+ break;
227
+ } catch (error) {
228
+ onSseError == null ? void 0 : onSseError(error);
229
+ if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
230
+ break;
231
+ }
232
+ const backoff = Math.min(
233
+ retryDelay * 2 ** (attempt - 1),
234
+ sseMaxRetryDelay ?? 3e4
235
+ );
236
+ await sleep(backoff);
237
+ }
238
+ }
239
+ };
240
+ const stream = createStream();
241
+ return { stream };
242
+ };
243
+ const separatorArrayExplode = (style) => {
244
+ switch (style) {
245
+ case "label":
246
+ return ".";
247
+ case "matrix":
248
+ return ";";
249
+ case "simple":
250
+ return ",";
251
+ default:
252
+ return "&";
253
+ }
254
+ };
255
+ const separatorArrayNoExplode = (style) => {
256
+ switch (style) {
257
+ case "form":
258
+ return ",";
259
+ case "pipeDelimited":
260
+ return "|";
261
+ case "spaceDelimited":
262
+ return "%20";
263
+ default:
264
+ return ",";
265
+ }
266
+ };
267
+ const separatorObjectExplode = (style) => {
268
+ switch (style) {
269
+ case "label":
270
+ return ".";
271
+ case "matrix":
272
+ return ";";
273
+ case "simple":
274
+ return ",";
275
+ default:
276
+ return "&";
277
+ }
278
+ };
279
+ const serializeArrayParam = ({
280
+ allowReserved,
281
+ explode,
282
+ name,
283
+ style,
284
+ value
285
+ }) => {
286
+ if (!explode) {
287
+ const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
288
+ switch (style) {
289
+ case "label":
290
+ return `.${joinedValues2}`;
291
+ case "matrix":
292
+ return `;${name}=${joinedValues2}`;
293
+ case "simple":
294
+ return joinedValues2;
295
+ default:
296
+ return `${name}=${joinedValues2}`;
297
+ }
298
+ }
299
+ const separator = separatorArrayExplode(style);
300
+ const joinedValues = value.map((v) => {
301
+ if (style === "label" || style === "simple") {
302
+ return allowReserved ? v : encodeURIComponent(v);
303
+ }
304
+ return serializePrimitiveParam({
305
+ allowReserved,
306
+ name,
307
+ value: v
308
+ });
309
+ }).join(separator);
310
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
311
+ };
312
+ const serializePrimitiveParam = ({
313
+ allowReserved,
314
+ name,
315
+ value
316
+ }) => {
317
+ if (value === void 0 || value === null) {
318
+ return "";
319
+ }
320
+ if (typeof value === "object") {
321
+ throw new Error(
322
+ "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these."
323
+ );
324
+ }
325
+ return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
326
+ };
327
+ const serializeObjectParam = ({
328
+ allowReserved,
329
+ explode,
330
+ name,
331
+ style,
332
+ value,
333
+ valueOnly
334
+ }) => {
335
+ if (value instanceof Date) {
336
+ return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
337
+ }
338
+ if (style !== "deepObject" && !explode) {
339
+ let values = [];
340
+ Object.entries(value).forEach(([key, v]) => {
341
+ values = [
342
+ ...values,
343
+ key,
344
+ allowReserved ? v : encodeURIComponent(v)
345
+ ];
346
+ });
347
+ const joinedValues2 = values.join(",");
348
+ switch (style) {
349
+ case "form":
350
+ return `${name}=${joinedValues2}`;
351
+ case "label":
352
+ return `.${joinedValues2}`;
353
+ case "matrix":
354
+ return `;${name}=${joinedValues2}`;
355
+ default:
356
+ return joinedValues2;
357
+ }
358
+ }
359
+ const separator = separatorObjectExplode(style);
360
+ const joinedValues = Object.entries(value).map(
361
+ ([key, v]) => serializePrimitiveParam({
362
+ allowReserved,
363
+ name: style === "deepObject" ? `${name}[${key}]` : key,
364
+ value: v
365
+ })
366
+ ).join(separator);
367
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
368
+ };
369
+ const PATH_PARAM_RE = /\{[^{}]+\}/g;
370
+ const defaultPathSerializer = ({ path, url: _url }) => {
371
+ let url = _url;
372
+ const matches = _url.match(PATH_PARAM_RE);
373
+ if (matches) {
374
+ for (const match of matches) {
375
+ let explode = false;
376
+ let name = match.substring(1, match.length - 1);
377
+ let style = "simple";
378
+ if (name.endsWith("*")) {
379
+ explode = true;
380
+ name = name.substring(0, name.length - 1);
381
+ }
382
+ if (name.startsWith(".")) {
383
+ name = name.substring(1);
384
+ style = "label";
385
+ } else if (name.startsWith(";")) {
386
+ name = name.substring(1);
387
+ style = "matrix";
388
+ }
389
+ const value = path[name];
390
+ if (value === void 0 || value === null) {
391
+ continue;
392
+ }
393
+ if (Array.isArray(value)) {
394
+ url = url.replace(
395
+ match,
396
+ serializeArrayParam({ explode, name, style, value })
397
+ );
398
+ continue;
399
+ }
400
+ if (typeof value === "object") {
401
+ url = url.replace(
402
+ match,
403
+ serializeObjectParam({
404
+ explode,
405
+ name,
406
+ style,
407
+ value,
408
+ valueOnly: true
409
+ })
410
+ );
411
+ continue;
412
+ }
413
+ if (style === "matrix") {
414
+ url = url.replace(
415
+ match,
416
+ `;${serializePrimitiveParam({
417
+ name,
418
+ value
419
+ })}`
420
+ );
421
+ continue;
422
+ }
423
+ const replaceValue = encodeURIComponent(
424
+ style === "label" ? `.${value}` : value
425
+ );
426
+ url = url.replace(match, replaceValue);
427
+ }
428
+ }
429
+ return url;
430
+ };
431
+ const getUrl = ({
432
+ baseUrl,
433
+ path,
434
+ query,
435
+ querySerializer,
436
+ url: _url
437
+ }) => {
438
+ const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
439
+ let url = (baseUrl ?? "") + pathUrl;
440
+ if (path) {
441
+ url = defaultPathSerializer({ path, url });
442
+ }
443
+ let search = query ? querySerializer(query) : "";
444
+ if (search.startsWith("?")) {
445
+ search = search.substring(1);
446
+ }
447
+ if (search) {
448
+ url += `?${search}`;
449
+ }
450
+ return url;
451
+ };
452
+ function getValidRequestBody(options) {
453
+ const hasBody = options.body !== void 0;
454
+ const isSerializedBody = hasBody && options.bodySerializer;
455
+ if (isSerializedBody) {
456
+ if ("serializedBody" in options) {
457
+ const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
458
+ return hasSerializedBody ? options.serializedBody : null;
459
+ }
460
+ return options.body !== "" ? options.body : null;
461
+ }
462
+ if (hasBody) {
463
+ return options.body;
464
+ }
465
+ return void 0;
466
+ }
467
+ const getAuthToken = async (auth, callback) => {
468
+ const token = typeof callback === "function" ? await callback(auth) : callback;
469
+ if (!token) {
470
+ return;
471
+ }
472
+ if (auth.scheme === "bearer") {
473
+ return `Bearer ${token}`;
474
+ }
475
+ if (auth.scheme === "basic") {
476
+ return `Basic ${btoa(token)}`;
477
+ }
478
+ return token;
479
+ };
480
+ const createQuerySerializer = ({
481
+ parameters = {},
482
+ ...args
483
+ } = {}) => {
484
+ const querySerializer = (queryParams) => {
485
+ const search = [];
486
+ if (queryParams && typeof queryParams === "object") {
487
+ for (const name in queryParams) {
488
+ const value = queryParams[name];
489
+ if (value === void 0 || value === null) {
490
+ continue;
491
+ }
492
+ const options = parameters[name] || args;
493
+ if (Array.isArray(value)) {
494
+ const serializedArray = serializeArrayParam({
495
+ allowReserved: options.allowReserved,
496
+ explode: true,
497
+ name,
498
+ style: "form",
499
+ value,
500
+ ...options.array
501
+ });
502
+ if (serializedArray) search.push(serializedArray);
503
+ } else if (typeof value === "object") {
504
+ const serializedObject = serializeObjectParam({
505
+ allowReserved: options.allowReserved,
506
+ explode: true,
507
+ name,
508
+ style: "deepObject",
509
+ value,
510
+ ...options.object
511
+ });
512
+ if (serializedObject) search.push(serializedObject);
513
+ } else {
514
+ const serializedPrimitive = serializePrimitiveParam({
515
+ allowReserved: options.allowReserved,
516
+ name,
517
+ value
518
+ });
519
+ if (serializedPrimitive) search.push(serializedPrimitive);
520
+ }
521
+ }
522
+ }
523
+ return search.join("&");
524
+ };
525
+ return querySerializer;
526
+ };
527
+ const getParseAs = (contentType) => {
528
+ var _a;
529
+ if (!contentType) {
530
+ return "stream";
531
+ }
532
+ const cleanContent = (_a = contentType.split(";")[0]) == null ? void 0 : _a.trim();
533
+ if (!cleanContent) {
534
+ return;
535
+ }
536
+ if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
537
+ return "json";
538
+ }
539
+ if (cleanContent === "multipart/form-data") {
540
+ return "formData";
541
+ }
542
+ if (["application/", "audio/", "image/", "video/"].some(
543
+ (type) => cleanContent.startsWith(type)
544
+ )) {
545
+ return "blob";
546
+ }
547
+ if (cleanContent.startsWith("text/")) {
548
+ return "text";
549
+ }
550
+ return;
551
+ };
552
+ const checkForExistence = (options, name) => {
553
+ var _a, _b;
554
+ if (!name) {
555
+ return false;
556
+ }
557
+ if (options.headers.has(name) || ((_a = options.query) == null ? void 0 : _a[name]) || ((_b = options.headers.get("Cookie")) == null ? void 0 : _b.includes(`${name}=`))) {
558
+ return true;
559
+ }
560
+ return false;
561
+ };
562
+ const setAuthParams = async ({
563
+ security,
564
+ ...options
565
+ }) => {
566
+ for (const auth of security) {
567
+ if (checkForExistence(options, auth.name)) {
568
+ continue;
569
+ }
570
+ const token = await getAuthToken(auth, options.auth);
571
+ if (!token) {
572
+ continue;
573
+ }
574
+ const name = auth.name ?? "Authorization";
575
+ switch (auth.in) {
576
+ case "query":
577
+ if (!options.query) {
578
+ options.query = {};
579
+ }
580
+ options.query[name] = token;
581
+ break;
582
+ case "cookie":
583
+ options.headers.append("Cookie", `${name}=${token}`);
584
+ break;
585
+ case "header":
586
+ default:
587
+ options.headers.set(name, token);
588
+ break;
589
+ }
590
+ }
591
+ };
592
+ const buildUrl = (options) => getUrl({
593
+ baseUrl: options.baseUrl,
594
+ path: options.path,
595
+ query: options.query,
596
+ querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
597
+ url: options.url
598
+ });
599
+ const mergeConfigs = (a, b) => {
600
+ var _a;
601
+ const config = { ...a, ...b };
602
+ if ((_a = config.baseUrl) == null ? void 0 : _a.endsWith("/")) {
603
+ config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
604
+ }
605
+ config.headers = mergeHeaders(a.headers, b.headers);
606
+ return config;
607
+ };
608
+ const headersEntries = (headers) => {
609
+ const entries = [];
610
+ headers.forEach((value, key) => {
611
+ entries.push([key, value]);
612
+ });
613
+ return entries;
614
+ };
615
+ const mergeHeaders = (...headers) => {
616
+ const mergedHeaders = new Headers();
617
+ for (const header of headers) {
618
+ if (!header) {
619
+ continue;
620
+ }
621
+ const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
622
+ for (const [key, value] of iterator) {
623
+ if (value === null) {
624
+ mergedHeaders.delete(key);
625
+ } else if (Array.isArray(value)) {
626
+ for (const v of value) {
627
+ mergedHeaders.append(key, v);
628
+ }
629
+ } else if (value !== void 0) {
630
+ mergedHeaders.set(
631
+ key,
632
+ typeof value === "object" ? JSON.stringify(value) : value
633
+ );
634
+ }
635
+ }
636
+ }
637
+ return mergedHeaders;
638
+ };
639
+ class Interceptors {
640
+ constructor() {
641
+ __publicField(this, "fns", []);
642
+ }
643
+ clear() {
644
+ this.fns = [];
645
+ }
646
+ eject(id) {
647
+ const index = this.getInterceptorIndex(id);
648
+ if (this.fns[index]) {
649
+ this.fns[index] = null;
650
+ }
651
+ }
652
+ exists(id) {
653
+ const index = this.getInterceptorIndex(id);
654
+ return Boolean(this.fns[index]);
655
+ }
656
+ getInterceptorIndex(id) {
657
+ if (typeof id === "number") {
658
+ return this.fns[id] ? id : -1;
659
+ }
660
+ return this.fns.indexOf(id);
661
+ }
662
+ update(id, fn) {
663
+ const index = this.getInterceptorIndex(id);
664
+ if (this.fns[index]) {
665
+ this.fns[index] = fn;
666
+ return id;
667
+ }
668
+ return false;
669
+ }
670
+ use(fn) {
671
+ this.fns.push(fn);
672
+ return this.fns.length - 1;
673
+ }
674
+ }
675
+ const createInterceptors = () => ({
676
+ error: new Interceptors(),
677
+ request: new Interceptors(),
678
+ response: new Interceptors()
679
+ });
680
+ const defaultQuerySerializer = createQuerySerializer({
681
+ allowReserved: false,
682
+ array: {
683
+ explode: true,
684
+ style: "form"
685
+ },
686
+ object: {
687
+ explode: true,
688
+ style: "deepObject"
689
+ }
690
+ });
691
+ const defaultHeaders = {
692
+ "Content-Type": "application/json"
693
+ };
694
+ const createConfig = (override = {}) => ({
695
+ ...jsonBodySerializer,
696
+ headers: defaultHeaders,
697
+ parseAs: "auto",
698
+ querySerializer: defaultQuerySerializer,
699
+ ...override
700
+ });
701
+ const createClient = (config = {}) => {
702
+ let _config = mergeConfigs(createConfig(), config);
703
+ const getConfig = () => ({ ..._config });
704
+ const setConfig = (config2) => {
705
+ _config = mergeConfigs(_config, config2);
706
+ return getConfig();
707
+ };
708
+ const interceptors = createInterceptors();
709
+ const beforeRequest = async (options) => {
710
+ const opts = {
711
+ ..._config,
712
+ ...options,
713
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
714
+ headers: mergeHeaders(_config.headers, options.headers),
715
+ serializedBody: void 0
716
+ };
717
+ if (opts.security) {
718
+ await setAuthParams({
719
+ ...opts,
720
+ security: opts.security
721
+ });
722
+ }
723
+ if (opts.requestValidator) {
724
+ await opts.requestValidator(opts);
725
+ }
726
+ if (opts.body !== void 0 && opts.bodySerializer) {
727
+ opts.serializedBody = opts.bodySerializer(opts.body);
728
+ }
729
+ if (opts.body === void 0 || opts.serializedBody === "") {
730
+ opts.headers.delete("Content-Type");
731
+ }
732
+ const url = buildUrl(opts);
733
+ return { opts, url };
734
+ };
735
+ const request = async (options) => {
736
+ const { opts, url } = await beforeRequest(options);
737
+ const requestInit = {
738
+ redirect: "follow",
739
+ ...opts,
740
+ body: getValidRequestBody(opts)
741
+ };
742
+ let request2 = new Request(url, requestInit);
743
+ for (const fn of interceptors.request.fns) {
744
+ if (fn) {
745
+ request2 = await fn(request2, opts);
746
+ }
747
+ }
748
+ const _fetch = opts.fetch;
749
+ let response;
750
+ try {
751
+ response = await _fetch(request2);
752
+ } catch (error2) {
753
+ let finalError2 = error2;
754
+ for (const fn of interceptors.error.fns) {
755
+ if (fn) {
756
+ finalError2 = await fn(
757
+ error2,
758
+ void 0,
759
+ request2,
760
+ opts
761
+ );
762
+ }
763
+ }
764
+ finalError2 = finalError2 || {};
765
+ if (opts.throwOnError) {
766
+ throw finalError2;
767
+ }
768
+ return opts.responseStyle === "data" ? void 0 : {
769
+ error: finalError2,
770
+ request: request2,
771
+ response: void 0
772
+ };
773
+ }
774
+ for (const fn of interceptors.response.fns) {
775
+ if (fn) {
776
+ response = await fn(response, request2, opts);
777
+ }
778
+ }
779
+ const result = {
780
+ request: request2,
781
+ response
782
+ };
783
+ if (response.ok) {
784
+ const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
785
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
786
+ let emptyData;
787
+ switch (parseAs) {
788
+ case "arrayBuffer":
789
+ case "blob":
790
+ case "text":
791
+ emptyData = await response[parseAs]();
792
+ break;
793
+ case "formData":
794
+ emptyData = new FormData();
795
+ break;
796
+ case "stream":
797
+ emptyData = response.body;
798
+ break;
799
+ case "json":
800
+ default:
801
+ emptyData = {};
802
+ break;
803
+ }
804
+ return opts.responseStyle === "data" ? emptyData : {
805
+ data: emptyData,
806
+ ...result
807
+ };
808
+ }
809
+ let data;
810
+ switch (parseAs) {
811
+ case "arrayBuffer":
812
+ case "blob":
813
+ case "formData":
814
+ case "json":
815
+ case "text":
816
+ data = await response[parseAs]();
817
+ break;
818
+ case "stream":
819
+ return opts.responseStyle === "data" ? response.body : {
820
+ data: response.body,
821
+ ...result
822
+ };
823
+ }
824
+ if (parseAs === "json") {
825
+ if (opts.responseValidator) {
826
+ await opts.responseValidator(data);
827
+ }
828
+ if (opts.responseTransformer) {
829
+ data = await opts.responseTransformer(data);
830
+ }
831
+ }
832
+ return opts.responseStyle === "data" ? data : {
833
+ data,
834
+ ...result
835
+ };
836
+ }
837
+ const textError = await response.text();
838
+ let jsonError;
839
+ try {
840
+ jsonError = JSON.parse(textError);
841
+ } catch {
842
+ }
843
+ const error = jsonError ?? textError;
844
+ let finalError = error;
845
+ for (const fn of interceptors.error.fns) {
846
+ if (fn) {
847
+ finalError = await fn(error, response, request2, opts);
848
+ }
849
+ }
850
+ finalError = finalError || {};
851
+ if (opts.throwOnError) {
852
+ throw finalError;
853
+ }
854
+ return opts.responseStyle === "data" ? void 0 : {
855
+ error: finalError,
856
+ ...result
857
+ };
858
+ };
859
+ const makeMethodFn = (method) => (options) => request({ ...options, method });
860
+ const makeSseFn = (method) => async (options) => {
861
+ const { opts, url } = await beforeRequest(options);
862
+ return createSseClient({
863
+ ...opts,
864
+ body: opts.body,
865
+ headers: opts.headers,
866
+ method,
867
+ onRequest: async (url2, init) => {
868
+ let request2 = new Request(url2, init);
869
+ for (const fn of interceptors.request.fns) {
870
+ if (fn) {
871
+ request2 = await fn(request2, opts);
872
+ }
873
+ }
874
+ return request2;
875
+ },
876
+ url
877
+ });
878
+ };
879
+ return {
880
+ buildUrl,
881
+ connect: makeMethodFn("CONNECT"),
882
+ delete: makeMethodFn("DELETE"),
883
+ get: makeMethodFn("GET"),
884
+ getConfig,
885
+ head: makeMethodFn("HEAD"),
886
+ interceptors,
887
+ options: makeMethodFn("OPTIONS"),
888
+ patch: makeMethodFn("PATCH"),
889
+ post: makeMethodFn("POST"),
890
+ put: makeMethodFn("PUT"),
891
+ request,
892
+ setConfig,
893
+ sse: {
894
+ connect: makeSseFn("CONNECT"),
895
+ delete: makeSseFn("DELETE"),
896
+ get: makeSseFn("GET"),
897
+ head: makeSseFn("HEAD"),
898
+ options: makeSseFn("OPTIONS"),
899
+ patch: makeSseFn("PATCH"),
900
+ post: makeSseFn("POST"),
901
+ put: makeSseFn("PUT"),
902
+ trace: makeSseFn("TRACE")
903
+ },
904
+ trace: makeMethodFn("TRACE")
905
+ };
906
+ };
907
+ const client = createClient(
908
+ createConfig({ baseUrl: "https://api.themolt.net" })
909
+ );
910
+ const registerAgent = (options) => (options.client ?? client).post({
911
+ url: "/auth/register",
912
+ ...options,
913
+ headers: {
914
+ "Content-Type": "application/json",
915
+ ...options.headers
916
+ }
917
+ });
918
+ ed.etc.sha512Sync = (...m) => {
919
+ const hash = createHash("sha512");
920
+ m.forEach((msg) => hash.update(msg));
921
+ return hash.digest();
922
+ };
923
+ const cryptoService = {
924
+ /**
925
+ * Generate a new Ed25519 keypair
926
+ */
927
+ async generateKeyPair() {
928
+ const privateKeyBytes = ed.utils.randomPrivateKey();
929
+ const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
930
+ const privateKey = Buffer.from(privateKeyBytes).toString("base64");
931
+ const publicKey = `ed25519:${Buffer.from(publicKeyBytes).toString("base64")}`;
932
+ const fingerprint = this.generateFingerprint(publicKeyBytes);
933
+ return { publicKey, privateKey, fingerprint };
934
+ },
935
+ /**
936
+ * Generate human-readable fingerprint from public key
937
+ * Format: A1B2-C3D4-E5F6-G7H8 (first 16 hex chars of SHA256)
938
+ */
939
+ generateFingerprint(publicKeyBytes) {
940
+ const hash = createHash("sha256").update(publicKeyBytes).digest("hex");
941
+ const segments = hash.slice(0, 16).toUpperCase().match(/.{4}/g) ?? [];
942
+ return segments.join("-");
943
+ },
944
+ /**
945
+ * Parse public key from string format
946
+ */
947
+ parsePublicKey(publicKey) {
948
+ const base64 = publicKey.replace(/^ed25519:/, "");
949
+ return new Uint8Array(Buffer.from(base64, "base64"));
950
+ },
951
+ /**
952
+ * Sign a message with private key
953
+ */
954
+ async sign(message, privateKeyBase64) {
955
+ const privateKeyBytes = new Uint8Array(
956
+ Buffer.from(privateKeyBase64, "base64")
957
+ );
958
+ const messageBytes = new TextEncoder().encode(message);
959
+ const signature = await ed.signAsync(messageBytes, privateKeyBytes);
960
+ return Buffer.from(signature).toString("base64");
961
+ },
962
+ /**
963
+ * Verify a signature against a message and public key
964
+ */
965
+ async verify(message, signature, publicKey) {
966
+ try {
967
+ const publicKeyBytes = this.parsePublicKey(publicKey);
968
+ const signatureBytes = new Uint8Array(Buffer.from(signature, "base64"));
969
+ const messageBytes = new TextEncoder().encode(message);
970
+ return await ed.verifyAsync(signatureBytes, messageBytes, publicKeyBytes);
971
+ } catch {
972
+ return false;
973
+ }
974
+ },
975
+ /**
976
+ * Create a signed message object
977
+ */
978
+ async createSignedMessage(message, privateKeyBase64, publicKey) {
979
+ const signature = await this.sign(message, privateKeyBase64);
980
+ return { message, signature, publicKey };
981
+ },
982
+ /**
983
+ * Verify a signed message object
984
+ */
985
+ async verifySignedMessage(signedMessage) {
986
+ return this.verify(
987
+ signedMessage.message,
988
+ signedMessage.signature,
989
+ signedMessage.publicKey
990
+ );
991
+ },
992
+ /**
993
+ * Generate a random challenge for authentication
994
+ */
995
+ generateChallenge() {
996
+ return `moltnet:challenge:${randomBytes(32).toString("hex")}:${Date.now()}`;
997
+ },
998
+ /**
999
+ * Derive public key from private key
1000
+ */
1001
+ async derivePublicKey(privateKeyBase64) {
1002
+ const privateKeyBytes = new Uint8Array(
1003
+ Buffer.from(privateKeyBase64, "base64")
1004
+ );
1005
+ const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
1006
+ return `ed25519:${Buffer.from(publicKeyBytes).toString("base64")}`;
1007
+ },
1008
+ /**
1009
+ * Get fingerprint from public key string
1010
+ */
1011
+ getFingerprintFromPublicKey(publicKey) {
1012
+ const publicKeyBytes = this.parsePublicKey(publicKey);
1013
+ return this.generateFingerprint(publicKeyBytes);
1014
+ },
1015
+ /**
1016
+ * Create a proof of identity ownership (for DCR metadata)
1017
+ */
1018
+ async createIdentityProof(identityId, privateKeyBase64) {
1019
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1020
+ const message = `moltnet:register:${identityId}:${timestamp}`;
1021
+ const signature = await this.sign(message, privateKeyBase64);
1022
+ return { message, signature, timestamp };
1023
+ },
1024
+ /**
1025
+ * Verify an identity proof
1026
+ */
1027
+ async verifyIdentityProof(proof, publicKey, expectedIdentityId) {
1028
+ const isValid = await this.verify(
1029
+ proof.message,
1030
+ proof.signature,
1031
+ publicKey
1032
+ );
1033
+ if (!isValid) return false;
1034
+ const expectedPrefix = `moltnet:register:${expectedIdentityId}:`;
1035
+ if (!proof.message.startsWith(expectedPrefix)) return false;
1036
+ const proofTime = new Date(proof.timestamp).getTime();
1037
+ const now = Date.now();
1038
+ const fiveMinutes = 5 * 60 * 1e3;
1039
+ if (now - proofTime > fiveMinutes) return false;
1040
+ return true;
1041
+ }
1042
+ };
1043
+ const DEFAULT_API_URL = "https://api.themolt.net";
1044
+ function buildMcpConfig(apiUrl) {
1045
+ const base = apiUrl.replace(/\/$/, "");
1046
+ return {
1047
+ mcpServers: {
1048
+ moltnet: {
1049
+ url: `${base}/mcp`,
1050
+ transport: "sse"
1051
+ }
1052
+ }
1053
+ };
1054
+ }
1055
+ async function register(options) {
1056
+ var _a;
1057
+ const apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
1058
+ const keyPair = await cryptoService.generateKeyPair();
1059
+ const client2 = createClient({ baseUrl: apiUrl });
1060
+ let data;
1061
+ try {
1062
+ const result = await registerAgent({
1063
+ client: client2,
1064
+ body: {
1065
+ public_key: keyPair.publicKey,
1066
+ voucher_code: options.voucherCode
1067
+ }
1068
+ });
1069
+ if (result.error) {
1070
+ const problem = result.error;
1071
+ throw problemToError(problem, problem.status ?? 500);
1072
+ }
1073
+ if (!result.data) {
1074
+ throw new NetworkError("Empty response from registration endpoint");
1075
+ }
1076
+ data = result.data;
1077
+ } catch (error) {
1078
+ if (error instanceof NetworkError || error instanceof RegistrationError) {
1079
+ throw error;
1080
+ }
1081
+ throw new NetworkError(
1082
+ error instanceof Error ? error.message : "Registration request failed",
1083
+ {
1084
+ detail: error instanceof Error ? (_a = error.cause) == null ? void 0 : _a.toString() : String(error)
1085
+ }
1086
+ );
1087
+ }
1088
+ return {
1089
+ identity: {
1090
+ publicKey: keyPair.publicKey,
1091
+ privateKey: keyPair.privateKey,
1092
+ fingerprint: data.fingerprint,
1093
+ identityId: data.identityId
1094
+ },
1095
+ credentials: {
1096
+ clientId: data.clientId,
1097
+ clientSecret: data.clientSecret
1098
+ },
1099
+ mcpConfig: buildMcpConfig(apiUrl),
1100
+ apiUrl
1101
+ };
1102
+ }
1103
+ const MoltNet = { register };
1104
+ export {
1105
+ MoltNet,
1106
+ MoltNetError,
1107
+ NetworkError,
1108
+ RegistrationError,
1109
+ buildMcpConfig,
1110
+ getConfigDir,
1111
+ getCredentialsPath,
1112
+ problemToError,
1113
+ readCredentials,
1114
+ register,
1115
+ writeCredentials,
1116
+ writeMcpConfig
1117
+ };
@@ -0,0 +1,29 @@
1
+ export interface RegisterOptions {
2
+ voucherCode: string;
3
+ apiUrl?: string;
4
+ }
5
+ export interface McpConfig {
6
+ mcpServers: {
7
+ moltnet: {
8
+ url: string;
9
+ transport: 'sse';
10
+ };
11
+ };
12
+ }
13
+ export interface RegisterResult {
14
+ identity: {
15
+ publicKey: string;
16
+ privateKey: string;
17
+ fingerprint: string;
18
+ identityId: string;
19
+ };
20
+ credentials: {
21
+ clientId: string;
22
+ clientSecret: string;
23
+ };
24
+ mcpConfig: McpConfig;
25
+ apiUrl: string;
26
+ }
27
+ export declare function buildMcpConfig(apiUrl: string): McpConfig;
28
+ export declare function register(options: RegisterOptions): Promise<RegisterResult>;
29
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE;QACV,OAAO,EAAE;YACP,GAAG,EAAE,MAAM,CAAC;YACZ,SAAS,EAAE,KAAK,CAAC;SAClB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAUxD;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAoDzB"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@themoltnet/sdk",
3
+ "version": "0.0.0-seed",
4
+ "type": "module",
5
+ "description": "MoltNet Agent SDK — register identity, store credentials, configure MCP",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "dependencies": {
18
+ "@noble/ed25519": "^2.0.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^20.11.0",
22
+ "typescript": "^5.3.3",
23
+ "vite": "^6.0.0",
24
+ "vitest": "^3.0.0",
25
+ "@moltnet/api-client": "0.1.0",
26
+ "@moltnet/crypto-service": "0.1.0"
27
+ },
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "scripts": {
32
+ "build": "vite build && tsc -b --emitDeclarationOnly --force",
33
+ "typecheck": "tsc -b --emitDeclarationOnly",
34
+ "test": "vitest run",
35
+ "lint": "eslint src/"
36
+ }
37
+ }