@m2msentinel/sdk 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@m2msentinel/sdk",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
+ "mcpName": "io.github.m2m-sentinel/m2m-sentinel-sdk",
4
5
  "publishConfig": {
5
6
  "access": "public"
6
7
  },
@@ -9,7 +10,8 @@
9
10
  "types": "index.d.ts",
10
11
  "bin": {
11
12
  "m2m-sentinel-mcp": "./mcp_server.js",
12
- "m2m-sentinel": "./mcp_server.js"
13
+ "m2m-sentinel": "./mcp_server.js",
14
+ "m2msentinel": "./mcp_server.js"
13
15
  },
14
16
  "license": "MIT",
15
17
  "homepage": "https://m2msentinel.com",
@@ -43,6 +45,7 @@
43
45
  "index.d.ts",
44
46
  "m2m_sentinel_sdk.js",
45
47
  "agent_adapter.js",
48
+ "x402_signer.js",
46
49
  "eliza_plugin.js",
47
50
  "mcp_server.js",
48
51
  "smithery.yaml",
@@ -50,4 +53,4 @@
50
53
  "typescript/"
51
54
  ]
52
55
  }
53
-
56
+
@@ -1,204 +1,218 @@
1
- export interface M2MSentinelClientOptions {
2
- apiKey?: string;
3
- baseUrl?: string;
4
- timeoutMs?: number;
5
- paymentSignature?: string;
6
- }
7
-
8
- interface M2MSentinelRequestOptions extends M2MSentinelClientOptions {
9
- operatorToken?: string;
10
- }
11
-
12
- export interface CreateSubscriptionIntentOptions extends M2MSentinelClientOptions {
13
- durationDays?: 31 | 90 | 365;
14
- renewExistingKey?: boolean;
15
- }
16
-
17
- export interface RecoveryChallengeOptions {
18
- txHash?: string;
19
- }
20
-
21
- export interface M2MSentinelErrorOptions {
22
- status?: number;
23
- body?: any;
24
- retryAfter?: string | null;
25
- paymentRequired?: any;
26
- paymentResponse?: any;
27
- }
28
-
29
- export class M2MSentinelError extends Error {
30
- public readonly status?: number;
31
- public readonly body?: any;
32
- public readonly retryAfter?: string | null;
33
- public readonly paymentRequired?: any;
34
- public readonly paymentResponse?: any;
35
-
36
- constructor(message: string, options: M2MSentinelErrorOptions = {}) {
37
- super(message);
38
- this.name = new.target.name;
39
- this.status = options.status;
40
- this.body = options.body;
41
- this.retryAfter = options.retryAfter || null;
42
- this.paymentRequired = options.paymentRequired || null;
43
- this.paymentResponse = options.paymentResponse || null;
44
- }
45
- }
46
-
47
- export class PaymentRequiredError extends M2MSentinelError {}
48
- export class RateLimitedError extends M2MSentinelError {}
49
- export class DataSourceUnavailableError extends M2MSentinelError {}
50
-
51
- const DEFAULT_BASE_URL = 'https://api.m2msentinel.com';
52
- const DEFAULT_TIMEOUT_MS = 30000;
53
-
54
- function parseX402Header(value: string | null): any {
55
- if (!value) return null;
56
- try { return JSON.parse(value); } catch { /* try v2 encoding */ }
57
- try {
58
- const normalized = value.replace(/-/g, '+').replace(/_/g, '/');
59
- const padded = normalized + '='.repeat((4 - normalized.length % 4) % 4);
60
- const bytes = Uint8Array.from(atob(padded), (character) => character.charCodeAt(0));
61
- return JSON.parse(new TextDecoder().decode(bytes));
62
- } catch {
63
- return null;
64
- }
65
- }
66
-
67
- export class M2MSentinelClient {
68
- private baseUrl: string;
69
- private apiKey?: string;
70
- private timeoutMs: number;
71
- private paymentSignature?: string;
72
-
73
- constructor(optionsOrBaseUrl: M2MSentinelClientOptions | string = {}, apiKey?: string) {
74
- const options = typeof optionsOrBaseUrl === 'string'
75
- ? { baseUrl: optionsOrBaseUrl, apiKey }
76
- : optionsOrBaseUrl;
77
- this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, '');
78
- this.apiKey = options.apiKey;
79
- this.timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS;
80
- this.paymentSignature = options.paymentSignature;
81
- }
82
-
83
- private async request<T>(method: 'GET' | 'POST', path: string, body?: any, options: M2MSentinelRequestOptions = {}): Promise<T> {
84
- const headers: Record<string, string> = {
85
- Accept: 'application/json'
86
- };
87
- if (body !== undefined) headers['Content-Type'] = 'application/json';
88
- const key = options.apiKey || this.apiKey;
89
- if (key) headers['x-api-key'] = key;
90
- if (options.operatorToken) headers.Authorization = `Bearer ${options.operatorToken}`;
91
- const paymentSignature = options.paymentSignature || this.paymentSignature;
92
- if (paymentSignature) headers['PAYMENT-SIGNATURE'] = paymentSignature;
93
-
94
- const controller = new AbortController();
95
- const timeout = setTimeout(() => controller.abort(), options.timeoutMs || this.timeoutMs);
96
- let response: Response;
97
- try {
98
- response = await fetch(this.baseUrl + path, {
99
- method,
100
- headers,
101
- body: body === undefined ? undefined : JSON.stringify(body),
102
- signal: controller.signal
103
- });
104
- } finally {
105
- clearTimeout(timeout);
106
- }
107
-
108
- const text = await response.text();
109
- let data: any = null;
110
- if (text) {
111
- try { data = JSON.parse(text); } catch { data = { raw: text }; }
112
- }
113
- if (response.ok) return data as T;
114
-
115
- const errorOptions = {
116
- status: response.status,
117
- body: data,
118
- retryAfter: response.headers.get('Retry-After'),
119
- paymentRequired: parseX402Header(response.headers.get('PAYMENT-REQUIRED')),
120
- paymentResponse: parseX402Header(response.headers.get('PAYMENT-RESPONSE')) || response.headers.get('PAYMENT-RESPONSE')
121
- };
122
- const message = data?.message || `M2M Sentinel HTTP ${response.status}`;
123
- if (response.status === 402) throw new PaymentRequiredError(message, errorOptions);
124
- if (response.status === 429) throw new RateLimitedError(message, errorOptions);
125
- if (response.status === 503 && data?.error === 'DATA_SOURCE_UNAVAILABLE') throw new DataSourceUnavailableError(message, errorOptions);
126
- throw new M2MSentinelError(message, errorOptions);
127
- }
128
-
129
- public getStatus() { return this.request<any>('GET', '/v1/status'); }
130
- public getPublicStats(days = 30) { return this.request<any>('GET', `/v1/stats?days=${encodeURIComponent(days)}`); }
131
- public getAggregateStats(days = 30) { return this.getPublicStats(days); }
132
- public getOperatorAggregateStats(days: number, operatorToken: string) {
133
- return this.request<any>('GET', `/v1/stats?days=${encodeURIComponent(days || 30)}`, undefined, { operatorToken });
134
- }
135
- public getPlans() { return this.request<any>('GET', '/v1/plans'); }
136
- public demoAudit(address: string) { return this.request<any>('GET', `/v1/demo/audit/${encodeURIComponent(address)}`); }
137
- public createFreeChallenge(userWallet: string) { return this.request<any>('POST', '/v1/subscribe/free/challenge', { userWallet }); }
138
- public claimFreeTier(intentId: string, signature: string) { return this.request<any>('POST', '/v1/subscribe/free/claim', { intentId, signature }); }
139
- public createSubscriptionIntent(tier: string, userWallet: string, options: CreateSubscriptionIntentOptions = {}) {
140
- const body: Record<string, any> = { tier, userWallet };
141
- if (options.durationDays !== undefined) body.durationDays = options.durationDays;
142
- if (options.renewExistingKey !== undefined) body.renewExistingKey = options.renewExistingKey;
143
- return this.request<any>('POST', '/v1/subscribe/intents', body, options);
144
- }
145
- public claimSubscription(intentId: string, signature: string, txHash: string) { return this.request<any>('POST', '/v1/subscribe/crypto', { intentId, signature, txHash }); }
146
- public createRecoveryChallenge(userWallet: string, options: RecoveryChallengeOptions = {}) {
147
- const body: Record<string, string> = { userWallet };
148
- if (options.txHash !== undefined) body.txHash = options.txHash;
149
- return this.request<any>('POST', '/v1/keys/recovery/challenge', body);
150
- }
151
- public claimRecoveredKey(intentId: string, signature: string) {
152
- return this.request<any>('POST', '/v1/keys/recovery/claim', { intentId, signature });
153
- }
154
- public auditContract(address: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/audit/${encodeURIComponent(address)}`, undefined, options); }
155
- public getCapabilityScore(address: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/security/score/${encodeURIComponent(address)}`, undefined, options); }
156
- /** Legacy name. The response is a capability coverage index, not a safety score. */
157
- public getSecurityScore(address: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/security/score/${encodeURIComponent(address)}`, undefined, options); }
158
- public getGasFees(options?: M2MSentinelClientOptions) { return this.request<any>('GET', '/v1/gas/fees', undefined, options); }
159
- public getDexMetrics(options?: M2MSentinelClientOptions) { return this.request<any>('GET', '/v1/dex/metrics', undefined, options); }
160
- public getTokenPrice(symbol: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/token/price/${encodeURIComponent(symbol)}`, undefined, options); }
161
- public getWhaleSignals(options?: M2MSentinelClientOptions) { return this.request<any>('GET', '/v1/whales/signals', undefined, options); }
162
- public getKeySelf() { return this.request<any>('GET', '/v1/keys/self'); }
163
- public revokeKey(confirm = true) { return this.request<any>('POST', '/v1/keys/revoke', { confirm }); }
164
- }
165
-
166
- export type SentinelPolicy = (analysis: any, context: { targetAddress: string; integration: string }) =>
167
- boolean | { allow: boolean; reason?: string } | Promise<boolean | { allow: boolean; reason?: string }>;
168
-
169
- export async function enforceCallerPolicy(policy: SentinelPolicy | undefined, analysis: any, context: { targetAddress: string; integration: string }) {
170
- if (typeof policy !== 'function') {
171
- throw new Error('[M2M Sentinel] A caller-defined policy function is required. Static capability observations are not a safety decision.');
172
- }
173
- const result = await policy(analysis, context);
174
- if (result === false || (typeof result === 'object' && result !== null && result.allow === false)) {
175
- const reason = typeof result === 'object' && result !== null && result.reason
176
- ? result.reason
177
- : 'caller-defined policy rejected the transaction';
178
- throw new Error(`[M2M Sentinel] Transaction blocked: ${reason}.`);
179
- }
180
- }
181
-
182
- export function createEthersSentinelMiddleware(apiKey?: string, baseUrl?: string, policy?: SentinelPolicy) {
183
- const client = new M2MSentinelClient({ apiKey, baseUrl });
184
- return {
185
- client,
186
- verifyContractBeforeTx: async (targetAddress: string, policyOverride?: SentinelPolicy) => {
187
- const audit = await client.auditContract(targetAddress);
188
- await enforceCallerPolicy(policyOverride || policy, audit, { targetAddress, integration: 'ethers' });
189
- return audit;
190
- }
191
- };
192
- }
193
-
194
- export function createViemSentinelInterceptor(apiKey?: string, baseUrl?: string, policy?: SentinelPolicy) {
195
- const client = new M2MSentinelClient({ apiKey, baseUrl });
196
- return {
197
- client,
198
- inspectSwapTarget: async (address: string, policyOverride?: SentinelPolicy) => {
199
- const analysis = await client.getCapabilityScore(address);
200
- await enforceCallerPolicy(policyOverride || policy, analysis, { targetAddress: address, integration: 'viem' });
201
- return analysis;
202
- }
203
- };
204
- }
1
+ export interface M2MSentinelClientOptions {
2
+ apiKey?: string;
3
+ baseUrl?: string;
4
+ timeoutMs?: number;
5
+ paymentSignature?: string;
6
+ }
7
+
8
+ interface M2MSentinelRequestOptions extends M2MSentinelClientOptions {
9
+ operatorToken?: string;
10
+ }
11
+
12
+ export interface CreateSubscriptionIntentOptions extends M2MSentinelClientOptions {
13
+ durationDays?: 31 | 90 | 365;
14
+ renewExistingKey?: boolean;
15
+ }
16
+
17
+ export interface RecoveryChallengeOptions {
18
+ txHash?: string;
19
+ }
20
+
21
+ export interface M2MSentinelErrorOptions {
22
+ status?: number;
23
+ body?: any;
24
+ retryAfter?: string | null;
25
+ paymentRequired?: any;
26
+ paymentResponse?: any;
27
+ }
28
+
29
+ export class M2MSentinelError extends Error {
30
+ public readonly status?: number;
31
+ public readonly body?: any;
32
+ public readonly retryAfter?: string | null;
33
+ public readonly paymentRequired?: any;
34
+ public readonly paymentResponse?: any;
35
+
36
+ constructor(message: string, options: M2MSentinelErrorOptions = {}) {
37
+ super(message);
38
+ this.name = new.target.name;
39
+ this.status = options.status;
40
+ this.body = options.body;
41
+ this.retryAfter = options.retryAfter || null;
42
+ this.paymentRequired = options.paymentRequired || null;
43
+ this.paymentResponse = options.paymentResponse || null;
44
+ }
45
+ }
46
+
47
+ export class PaymentRequiredError extends M2MSentinelError {}
48
+ export class RateLimitedError extends M2MSentinelError {}
49
+ export class DataSourceUnavailableError extends M2MSentinelError {}
50
+
51
+ const DEFAULT_BASE_URL = 'https://api.m2msentinel.com';
52
+ const DEFAULT_TIMEOUT_MS = 30000;
53
+
54
+ function parseX402Header(value: string | null): any {
55
+ if (!value) return null;
56
+ try { return JSON.parse(value); } catch { /* try v2 encoding */ }
57
+ try {
58
+ const normalized = value.replace(/-/g, '+').replace(/_/g, '/');
59
+ const padded = normalized + '='.repeat((4 - normalized.length % 4) % 4);
60
+ const bytes = Uint8Array.from(atob(padded), (character) => character.charCodeAt(0));
61
+ return JSON.parse(new TextDecoder().decode(bytes));
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+
67
+ export class M2MSentinelClient {
68
+ private baseUrl: string;
69
+ private apiKey?: string;
70
+ private timeoutMs: number;
71
+ private paymentSignature?: string;
72
+
73
+ constructor(optionsOrBaseUrl: M2MSentinelClientOptions | string = {}, apiKey?: string) {
74
+ const options = typeof optionsOrBaseUrl === 'string'
75
+ ? { baseUrl: optionsOrBaseUrl, apiKey }
76
+ : optionsOrBaseUrl;
77
+ this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, '');
78
+ this.apiKey = options.apiKey;
79
+ this.timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS;
80
+ this.paymentSignature = options.paymentSignature;
81
+ }
82
+
83
+ private async request<T>(method: 'GET' | 'POST', path: string, body?: any, options: M2MSentinelRequestOptions = {}): Promise<T> {
84
+ const headers: Record<string, string> = {
85
+ Accept: 'application/json'
86
+ };
87
+ if (body !== undefined) headers['Content-Type'] = 'application/json';
88
+ const key = options.apiKey || this.apiKey;
89
+ if (key) headers['x-api-key'] = key;
90
+ if (options.operatorToken) headers.Authorization = `Bearer ${options.operatorToken}`;
91
+ const paymentSignature = options.paymentSignature || this.paymentSignature;
92
+ if (paymentSignature) headers['PAYMENT-SIGNATURE'] = paymentSignature;
93
+
94
+ const controller = new AbortController();
95
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs || this.timeoutMs);
96
+ let response: Response;
97
+ try {
98
+ response = await fetch(this.baseUrl + path, {
99
+ method,
100
+ headers,
101
+ body: body === undefined ? undefined : JSON.stringify(body),
102
+ signal: controller.signal
103
+ });
104
+ } finally {
105
+ clearTimeout(timeout);
106
+ }
107
+
108
+ const text = await response.text();
109
+ let data: any = null;
110
+ if (text) {
111
+ try { data = JSON.parse(text); } catch { data = { raw: text }; }
112
+ }
113
+ if (response.ok) return data as T;
114
+
115
+ const errorOptions = {
116
+ status: response.status,
117
+ body: data,
118
+ retryAfter: response.headers.get('Retry-After'),
119
+ paymentRequired: parseX402Header(response.headers.get('PAYMENT-REQUIRED')),
120
+ paymentResponse: parseX402Header(response.headers.get('PAYMENT-RESPONSE')) || response.headers.get('PAYMENT-RESPONSE')
121
+ };
122
+ const message = data?.message || `M2M Sentinel HTTP ${response.status}`;
123
+ if (response.status === 402) throw new PaymentRequiredError(message, errorOptions);
124
+ if (response.status === 429) throw new RateLimitedError(message, errorOptions);
125
+ if (response.status === 503 && data?.error === 'DATA_SOURCE_UNAVAILABLE') throw new DataSourceUnavailableError(message, errorOptions);
126
+ throw new M2MSentinelError(message, errorOptions);
127
+ }
128
+
129
+ public getStatus() { return this.request<any>('GET', '/v1/status'); }
130
+ public getPublicStats(days = 30) { return this.request<any>('GET', `/v1/stats?days=${encodeURIComponent(days)}`); }
131
+ public getAggregateStats(days = 30) { return this.getPublicStats(days); }
132
+ public getOperatorAggregateStats(days: number, operatorToken: string) {
133
+ return this.request<any>('GET', `/v1/stats?days=${encodeURIComponent(days || 30)}`, undefined, { operatorToken });
134
+ }
135
+ public getPlans() { return this.request<any>('GET', '/v1/plans'); }
136
+ public demoAudit(address: string) { return this.request<any>('GET', `/v1/demo/audit/${encodeURIComponent(address)}`); }
137
+ public createFreeChallenge(userWallet: string) { return this.request<any>('POST', '/v1/subscribe/free/challenge', { userWallet }); }
138
+ public claimFreeTier(intentId: string, signature: string) { return this.request<any>('POST', '/v1/subscribe/free/claim', { intentId, signature }); }
139
+ public createSubscriptionIntent(tier: string, userWallet: string, options: CreateSubscriptionIntentOptions = {}) {
140
+ const body: Record<string, any> = { tier, userWallet };
141
+ if (options.durationDays !== undefined) body.durationDays = options.durationDays;
142
+ if (options.renewExistingKey !== undefined) body.renewExistingKey = options.renewExistingKey;
143
+ return this.request<any>('POST', '/v1/subscribe/intents', body, options);
144
+ }
145
+ public claimSubscription(intentId: string, signature: string, txHash: string) { return this.request<any>('POST', '/v1/subscribe/crypto', { intentId, signature, txHash }); }
146
+ public createRecoveryChallenge(userWallet: string, options: RecoveryChallengeOptions = {}) {
147
+ const body: Record<string, string> = { userWallet };
148
+ if (options.txHash !== undefined) body.txHash = options.txHash;
149
+ return this.request<any>('POST', '/v1/keys/recovery/challenge', body);
150
+ }
151
+ public claimRecoveredKey(intentId: string, signature: string) {
152
+ return this.request<any>('POST', '/v1/keys/recovery/claim', { intentId, signature });
153
+ }
154
+ public auditContract(address: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/audit/${encodeURIComponent(address)}`, undefined, options); }
155
+ public getCapabilityScore(address: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/security/score/${encodeURIComponent(address)}`, undefined, options); }
156
+ /** Legacy name. The response is a capability coverage index, not a safety score. */
157
+ public getSecurityScore(address: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/security/score/${encodeURIComponent(address)}`, undefined, options); }
158
+ public getGasFees(options?: M2MSentinelClientOptions) { return this.request<any>('GET', '/v1/gas/fees', undefined, options); }
159
+ public getDexMetrics(options?: M2MSentinelClientOptions) { return this.request<any>('GET', '/v1/dex/metrics', undefined, options); }
160
+ public getTokenPrice(symbol: string, options?: M2MSentinelClientOptions) { return this.request<any>('GET', `/v1/token/price/${encodeURIComponent(symbol)}`, undefined, options); }
161
+ public getWhaleSignals(options?: M2MSentinelClientOptions) { return this.request<any>('GET', '/v1/whales/signals', undefined, options); }
162
+ public getKeySelf() { return this.request<any>('GET', '/v1/keys/self'); }
163
+ public revokeKey(confirm = true) { return this.request<any>('POST', '/v1/keys/revoke', { confirm }); }
164
+ }
165
+
166
+ export type SentinelPolicy = (analysis: any, context: { targetAddress: string; integration: string }) =>
167
+ boolean | { allow: boolean; reason?: string } | Promise<boolean | { allow: boolean; reason?: string }>;
168
+
169
+ export async function enforceCallerPolicy(policy: SentinelPolicy | undefined, analysis: any, context: { targetAddress: string; integration: string }) {
170
+ if (typeof policy !== 'function') {
171
+ throw new Error('[M2M Sentinel] A caller-defined policy function is required. Static capability observations are not a safety decision.');
172
+ }
173
+ const result = await policy(analysis, context);
174
+ if (result === false || (typeof result === 'object' && result !== null && result.allow === false)) {
175
+ const reason = typeof result === 'object' && result !== null && result.reason
176
+ ? result.reason
177
+ : 'caller-defined policy rejected the transaction';
178
+ throw new Error(`[M2M Sentinel] Transaction blocked: ${reason}.`);
179
+ }
180
+ }
181
+
182
+ export function createEthersSentinelMiddleware(apiKey?: string, baseUrl?: string, policy?: SentinelPolicy) {
183
+ const client = new M2MSentinelClient({ apiKey, baseUrl });
184
+ return {
185
+ client,
186
+ verifyContractBeforeTx: async (targetAddress: string, policyOverride?: SentinelPolicy) => {
187
+ const audit = await client.auditContract(targetAddress);
188
+ await enforceCallerPolicy(policyOverride || policy, audit, { targetAddress, integration: 'ethers' });
189
+ return audit;
190
+ }
191
+ };
192
+ }
193
+
194
+ export function createViemSentinelInterceptor(apiKey?: string, baseUrl?: string, policy?: SentinelPolicy) {
195
+ const client = new M2MSentinelClient({ apiKey, baseUrl });
196
+ return {
197
+ client,
198
+ inspectSwapTarget: async (address: string, policyOverride?: SentinelPolicy) => {
199
+ const analysis = await client.getCapabilityScore(address);
200
+ await enforceCallerPolicy(policyOverride || policy, analysis, { targetAddress: address, integration: 'viem' });
201
+ return analysis;
202
+ }
203
+ };
204
+ }
205
+
206
+ export {
207
+ BASE_USDC_CONTRACT,
208
+ BASE_CHAIN_ID,
209
+ EXPECTED_PAYOUT_RECIPIENT,
210
+ DEFAULT_MAX_PRICE_USD,
211
+ X402SignerClientOptions,
212
+ X402PaymentChallenge,
213
+ X402SignedAuthorization,
214
+ parsePriceToUnits,
215
+ parsePaymentHeader,
216
+ X402SignerClient,
217
+ x402SignerClient
218
+ } from './x402';
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "m2m-sentinel-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Source-distributed TypeScript client for M2M Sentinel Base capability intelligence API",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",
@@ -11,4 +11,4 @@
11
11
  "devDependencies": {
12
12
  "typescript": "^5.0.0"
13
13
  }
14
- }
14
+ }