@mitralab.io/platform-sdk 1.0.7 → 1.0.9

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/dist/index.js CHANGED
@@ -1,31 +1,42 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- MitraApiError: () => MitraApiError,
24
- createClient: () => createClient
25
- });
26
- module.exports = __toCommonJS(index_exports);
1
+ // src/client.ts
2
+ import { encodePathSegment, expectObject } from "@mitralab.io/sdk-core";
27
3
 
28
4
  // src/utils/http-client.ts
5
+ var bearerCredentialPattern = /(Bearer\s+)\S+/gi;
6
+ function redactText(value, currentToken) {
7
+ const withoutBearerCredentials = value.replace(bearerCredentialPattern, "$1[REDACTED]");
8
+ return currentToken ? withoutBearerCredentials.split(currentToken).join("[REDACTED]") : withoutBearerCredentials;
9
+ }
10
+ function redactDetails(value, currentToken) {
11
+ if (typeof value === "string") return redactText(value, currentToken);
12
+ if (Array.isArray(value)) return value.map((item) => redactDetails(item, currentToken));
13
+ if (value && typeof value === "object") {
14
+ return Object.fromEntries(
15
+ Object.entries(value).map(([key, entry]) => [
16
+ redactText(key, currentToken),
17
+ redactDetails(entry, currentToken)
18
+ ])
19
+ );
20
+ }
21
+ return value;
22
+ }
23
+ function asErrorPayload(value) {
24
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
25
+ return value;
26
+ }
27
+ function optionalString(value) {
28
+ return typeof value === "string" ? value : void 0;
29
+ }
30
+ function buildRequestUrl(baseUrl, path, params) {
31
+ const url = `${baseUrl}${path}`;
32
+ if (!params) return url;
33
+ const searchParams = new URLSearchParams();
34
+ Object.entries(params).forEach(([key, value]) => {
35
+ if (value !== void 0) searchParams.append(key, String(value));
36
+ });
37
+ const queryString = searchParams.toString();
38
+ return queryString ? `${url}?${queryString}` : url;
39
+ }
29
40
  var HttpClient = class {
30
41
  baseUrl;
31
42
  tokenGetter;
@@ -64,19 +75,7 @@ var HttpClient = class {
64
75
  */
65
76
  async request(path, options = {}) {
66
77
  const { method = "GET", body, headers = {}, params, isRetry } = options;
67
- let url = `${this.baseUrl}${path}`;
68
- if (params) {
69
- const searchParams = new URLSearchParams();
70
- Object.entries(params).forEach(([key, value]) => {
71
- if (value !== void 0) {
72
- searchParams.append(key, String(value));
73
- }
74
- });
75
- const queryString = searchParams.toString();
76
- if (queryString) {
77
- url += `?${queryString}`;
78
- }
79
- }
78
+ const url = buildRequestUrl(this.baseUrl, path, params);
80
79
  const requestHeaders = {
81
80
  "Content-Type": "application/json",
82
81
  ...this.defaultHeaders,
@@ -89,8 +88,18 @@ var HttpClient = class {
89
88
  const response = await fetch(url, {
90
89
  method,
91
90
  headers: requestHeaders,
92
- body: body ? JSON.stringify(body) : void 0
91
+ body: body ? JSON.stringify(body) : void 0,
92
+ redirect: "manual"
93
93
  });
94
+ if (response.redirected || response.type === "opaqueredirect") {
95
+ const error = new MitraApiError(
96
+ "Redirected responses are not allowed",
97
+ response.status,
98
+ "REDIRECT_NOT_ALLOWED"
99
+ );
100
+ this.onError?.(error);
101
+ throw error;
102
+ }
94
103
  if (!response.ok) {
95
104
  if (response.status === 401 && !isRetry && this.onUnauthorized) {
96
105
  const refreshed = await this.onUnauthorized();
@@ -99,11 +108,14 @@ var HttpClient = class {
99
108
  }
100
109
  }
101
110
  const errorBody = await response.json().catch(() => ({}));
111
+ const errorPayload = asErrorPayload(errorBody);
112
+ const rawMessage = optionalString(errorPayload.message);
113
+ const rawCode = optionalString(errorPayload.error_code);
102
114
  const error = new MitraApiError(
103
- errorBody.message || `Request failed with status ${response.status}`,
115
+ redactText(rawMessage || `Request failed with status ${response.status}`, token),
104
116
  response.status,
105
- errorBody.error_code,
106
- errorBody
117
+ rawCode === void 0 ? void 0 : redactText(rawCode, token),
118
+ redactDetails(errorBody, token)
107
119
  );
108
120
  this.onError?.(error);
109
121
  throw error;
@@ -184,22 +196,31 @@ var MitraApiError = class extends Error {
184
196
  }
185
197
  };
186
198
 
199
+ // src/core-errors.ts
200
+ var coreErrors = {
201
+ configuration: (message) => new MitraApiError(message, 0, "INVALID_CONFIGURATION"),
202
+ invalidResponse: (message) => new MitraApiError(message, 200, "INVALID_RESPONSE")
203
+ };
204
+
187
205
  // src/modules/auth.ts
206
+ import { createAuthModule } from "@mitralab.io/sdk-core";
188
207
  var AuthModule = class {
189
208
  appId;
190
209
  _currentUser = null;
191
- _accessToken = null;
192
- _refreshToken = null;
210
+ #accessToken = null;
211
+ #refreshToken = null;
193
212
  refreshPromise = null;
194
213
  listeners = /* @__PURE__ */ new Set();
195
214
  storageKey;
196
215
  publicClient;
197
216
  authedClient;
217
+ currentUserApi;
198
218
  constructor(appId, iamBaseUrl) {
199
219
  this.appId = appId;
200
220
  this.storageKey = `mitra_auth_${appId}`;
201
221
  this.publicClient = new HttpClient({ baseUrl: iamBaseUrl, getToken: () => null });
202
- this.authedClient = new HttpClient({ baseUrl: iamBaseUrl, getToken: () => this._accessToken });
222
+ this.authedClient = new HttpClient({ baseUrl: iamBaseUrl, getToken: () => this.#accessToken });
223
+ this.currentUserApi = createAuthModule(this.authedClient, coreErrors);
203
224
  this.loadFromStorage();
204
225
  }
205
226
  /** The currently authenticated user, or null. */
@@ -208,11 +229,11 @@ var AuthModule = class {
208
229
  }
209
230
  /** The current JWT access token, or null. */
210
231
  get accessToken() {
211
- return this._accessToken;
232
+ return this.#accessToken;
212
233
  }
213
234
  /** Whether a user is currently authenticated (local check, not server-validated). */
214
235
  get isAuthenticated() {
215
- return this._currentUser !== null && this._accessToken !== null;
236
+ return this._currentUser !== null && this.#accessToken !== null;
216
237
  }
217
238
  /**
218
239
  * Signs in a user with email and password.
@@ -237,9 +258,9 @@ var AuthModule = class {
237
258
  "/api/v1/auth/login",
238
259
  { ...credentials, appId: this.appId }
239
260
  );
240
- this._accessToken = tokenResponse.accessToken;
241
- this._refreshToken = tokenResponse.refreshToken;
242
- const user = await this.authedClient.get("/api/v1/auth/me");
261
+ this.#accessToken = tokenResponse.accessToken;
262
+ this.#refreshToken = tokenResponse.refreshToken;
263
+ const user = await this.getCurrentUser();
243
264
  this.setAuthState(user, tokenResponse.accessToken, tokenResponse.refreshToken);
244
265
  return user;
245
266
  }
@@ -299,7 +320,7 @@ var AuthModule = class {
299
320
  * ```
300
321
  */
301
322
  async refreshSession() {
302
- if (!this._refreshToken) return false;
323
+ if (!this.#refreshToken) return false;
303
324
  if (this.refreshPromise) return this.refreshPromise;
304
325
  this.refreshPromise = this.doRefresh();
305
326
  try {
@@ -323,9 +344,9 @@ var AuthModule = class {
323
344
  * ```
324
345
  */
325
346
  async me() {
326
- if (!this._accessToken) return null;
347
+ if (!this.#accessToken) return null;
327
348
  try {
328
- const user = await this.authedClient.get("/api/v1/auth/me");
349
+ const user = await this.getCurrentUser();
329
350
  this._currentUser = user;
330
351
  this.saveToStorage();
331
352
  this.notifyListeners();
@@ -366,7 +387,7 @@ var AuthModule = class {
366
387
  * ```
367
388
  */
368
389
  setToken(token, saveToStorage = true) {
369
- this._accessToken = token;
390
+ this.#accessToken = token;
370
391
  if (saveToStorage) {
371
392
  this.saveToStorage();
372
393
  }
@@ -417,11 +438,11 @@ var AuthModule = class {
417
438
  try {
418
439
  const tokenResponse = await this.publicClient.post(
419
440
  "/api/v1/auth/refresh-token",
420
- { refreshToken: this._refreshToken }
441
+ { refreshToken: this.#refreshToken }
421
442
  );
422
- this._accessToken = tokenResponse.accessToken;
423
- this._refreshToken = tokenResponse.refreshToken;
424
- const user = await this.authedClient.get("/api/v1/auth/me");
443
+ this.#accessToken = tokenResponse.accessToken;
444
+ this.#refreshToken = tokenResponse.refreshToken;
445
+ const user = await this.getCurrentUser();
425
446
  this.setAuthState(user, tokenResponse.accessToken, tokenResponse.refreshToken);
426
447
  return true;
427
448
  } catch {
@@ -431,15 +452,19 @@ var AuthModule = class {
431
452
  }
432
453
  setAuthState(user, token, refreshToken) {
433
454
  this._currentUser = user;
434
- this._accessToken = token;
435
- this._refreshToken = refreshToken;
455
+ this.#accessToken = token;
456
+ this.#refreshToken = refreshToken;
436
457
  this.saveToStorage();
437
458
  this.notifyListeners();
438
459
  }
460
+ async getCurrentUser() {
461
+ const user = await this.currentUserApi.me();
462
+ return { ...user, tenantId: user.tenant.id };
463
+ }
439
464
  clearAuthState() {
440
465
  this._currentUser = null;
441
- this._accessToken = null;
442
- this._refreshToken = null;
466
+ this.#accessToken = null;
467
+ this.#refreshToken = null;
443
468
  this.removeFromStorage();
444
469
  this.notifyListeners();
445
470
  }
@@ -459,8 +484,8 @@ var AuthModule = class {
459
484
  this.storageKey,
460
485
  JSON.stringify({
461
486
  user: this._currentUser,
462
- token: this._accessToken,
463
- refreshToken: this._refreshToken
487
+ token: this.#accessToken,
488
+ refreshToken: this.#refreshToken
464
489
  })
465
490
  );
466
491
  } catch {
@@ -473,8 +498,8 @@ var AuthModule = class {
473
498
  if (stored) {
474
499
  const { user, token, refreshToken } = JSON.parse(stored);
475
500
  this._currentUser = user;
476
- this._accessToken = token;
477
- this._refreshToken = refreshToken ?? null;
501
+ this.#accessToken = token;
502
+ this.#refreshToken = refreshToken ?? null;
478
503
  }
479
504
  } catch {
480
505
  this.removeFromStorage();
@@ -490,208 +515,121 @@ var AuthModule = class {
490
515
  };
491
516
 
492
517
  // src/modules/entities.ts
518
+ import {
519
+ createEntitiesModule
520
+ } from "@mitralab.io/sdk-core";
493
521
  var EntitiesModule = class _EntitiesModule {
494
- httpClient;
495
- dataSourceId;
496
- tableProxies = /* @__PURE__ */ new Map();
497
- constructor(httpClient, dataSourceId) {
522
+ constructor(httpClient, _dataSourceId) {
498
523
  this.httpClient = httpClient;
499
- this.dataSourceId = dataSourceId;
524
+ this.core = createEntitiesModule(httpClient, coreErrors);
500
525
  }
526
+ core;
501
527
  static createProxy(httpClient, dataSourceId) {
502
528
  const instance = new _EntitiesModule(httpClient, dataSourceId);
503
529
  return new Proxy(instance, {
504
- get: (target, prop) => {
505
- if (prop in target) {
506
- return target[prop];
530
+ get(target, property, receiver) {
531
+ if (typeof property !== "string" || property in target) {
532
+ return Reflect.get(target, property, receiver);
507
533
  }
508
- return target.getTable(prop);
534
+ return target.getTable(property);
509
535
  }
510
536
  });
511
537
  }
512
- setDataSourceId(dataSourceId) {
513
- this.dataSourceId = dataSourceId;
514
- this.tableProxies.clear();
538
+ /**
539
+ * Preserved for Platform SDK 1.x compatibility.
540
+ * Records now resolve the app from authenticated context instead of a data source path.
541
+ */
542
+ setDataSourceId(_dataSourceId) {
543
+ this.core = createEntitiesModule(this.httpClient, coreErrors);
515
544
  }
516
545
  getTable(tableName) {
517
- if (!this.tableProxies.has(tableName)) {
518
- this.tableProxies.set(tableName, this.createTableAccessor(tableName));
519
- }
520
- return this.tableProxies.get(tableName);
521
- }
522
- createTableAccessor(tableName) {
523
- const basePath = `/api/v1/data-sources/${this.dataSourceId}/tables/${tableName}/records`;
524
- return {
525
- list: async (sortOrOptions, limit, skip, fields) => {
526
- let params;
527
- if (typeof sortOrOptions === "string" || sortOrOptions === void 0) {
528
- params = {
529
- sort: sortOrOptions,
530
- limit,
531
- skip,
532
- fields: fields?.join(",")
533
- };
534
- } else {
535
- params = {
536
- sort: sortOrOptions.sort,
537
- limit: sortOrOptions.limit,
538
- skip: sortOrOptions.skip,
539
- fields: sortOrOptions.fields?.join(",")
540
- };
541
- }
542
- const response = await this.httpClient.get(basePath, params);
543
- return response.data;
544
- },
545
- filter: async (query, sort, limit, skip, fields) => {
546
- const params = {
547
- q: JSON.stringify(query),
548
- sort,
549
- limit,
550
- skip,
551
- fields: fields?.join(",")
552
- };
553
- const response = await this.httpClient.get(basePath, params);
554
- return response.data;
555
- },
556
- get: async (id) => {
557
- return this.httpClient.get(`${basePath}/${id}`);
558
- },
559
- create: async (data) => {
560
- return this.httpClient.post(basePath, data);
561
- },
562
- update: async (id, data) => {
563
- return this.httpClient.put(`${basePath}/${id}`, data);
564
- },
565
- delete: async (id) => {
566
- return this.httpClient.delete(`${basePath}/${id}`);
567
- },
568
- deleteMany: async (query) => {
569
- return this.httpClient.delete(basePath, {
570
- q: JSON.stringify(query)
571
- });
572
- },
573
- bulkCreate: async (data) => {
574
- return this.httpClient.post(`${basePath}/bulk`, data);
575
- }
576
- };
546
+ return this.core.getTable(tableName);
577
547
  }
578
548
  };
579
549
 
580
550
  // src/modules/functions.ts
551
+ import {
552
+ createFunctionsModule
553
+ } from "@mitralab.io/sdk-core";
581
554
  var FunctionsModule = class {
582
- httpClient;
555
+ core;
583
556
  constructor(httpClient) {
584
- this.httpClient = httpClient;
557
+ this.core = createFunctionsModule(httpClient, { emptyInput: "omit-body" }, coreErrors);
585
558
  }
586
559
  /**
587
- * Executes a serverless function by ID.
588
- *
589
- * Triggers the function's current published version with the provided input.
590
- *
591
- * @param functionId - UUID of the function to execute.
592
- * @param input - Input data to pass to the function.
593
- * @returns The execution result with status, output, and metadata.
594
- * @throws {MitraApiError} On function not found (404) or unauthorized (401).
595
- *
596
- * @example
597
- * ```typescript
598
- * const execution = await mitra.functions.execute('fn-id', { key: 'value' });
599
- * console.log(execution.status, execution.output);
600
- * ```
560
+ * Executes a Function using the Platform SDK 1.x server-default invocation semantics.
561
+ * The runtime SDK uses an explicit invocation header instead.
601
562
  */
602
563
  async execute(functionId, input) {
603
- return this.httpClient.post(
604
- `/api/v1/functions/${functionId}/execute`,
605
- input ? { input } : void 0
606
- );
564
+ const execution = await this.core.execute(functionId, input);
565
+ if (execution.input === null) {
566
+ throw coreErrors.invalidResponse(
567
+ "Function execution response has an invalid input field"
568
+ );
569
+ }
570
+ return { ...execution, input: execution.input };
607
571
  }
608
572
  };
609
573
 
610
574
  // src/modules/integration.ts
575
+ import {
576
+ createIntegrationModule
577
+ } from "@mitralab.io/sdk-core";
611
578
  var IntegrationModule = class {
612
- httpClient;
579
+ core;
613
580
  constructor(httpClient) {
614
- this.httpClient = httpClient;
581
+ this.core = createIntegrationModule(httpClient, coreErrors);
615
582
  }
616
- /**
617
- * Executes a pre-defined integration resource by ID.
618
- *
619
- * The resource's endpoint, method, and body are resolved server-side
620
- * using the provided parameters. Only declared parameters can be passed.
621
- *
622
- * @param resourceId - UUID of the integration resource.
623
- * @param params - Named parameters declared in the resource's params schema.
624
- * @returns Proxy result with status, headers, body, and execution metadata.
625
- * @throws {MitraApiError} On resource not found (404) or external API failure.
626
- *
627
- * @example
628
- * ```typescript
629
- * const result = await mitra.integration.executeResource('resource-id', {
630
- * descricao: 'Notebook',
631
- * limit: 10,
632
- * });
633
- * console.log(result.body);
634
- * ```
635
- */
636
- async executeResource(resourceId, params) {
637
- return this.httpClient.post(
638
- `/api/v1/proxy/resources/${resourceId}/execute`,
639
- { params }
640
- );
583
+ executeResource(resourceId, params) {
584
+ return this.core.executeResource(resourceId, params);
641
585
  }
642
- /**
643
- * Executes a proxied HTTP request through an integration config.
644
- *
645
- * The Mitra server handles authentication and injects credentials automatically.
646
- * Note: integrations configured with RESOURCE_ONLY mode will block direct proxy access.
647
- *
648
- * @param configId - UUID of the integration config.
649
- * @param request - The HTTP request to proxy (method, endpoint, body, etc.).
650
- * @returns Proxy result with status, headers, body, and execution metadata.
651
- * @throws {MitraApiError} On config not found (404) or external API failure.
652
- */
653
- async execute(configId, request) {
654
- return this.httpClient.post(
655
- `/api/v1/proxy/template-configs/${configId}/execute`,
656
- { ...request, source: "SDK" }
657
- );
586
+ execute(configId, request) {
587
+ return this.core.execute(configId, request);
658
588
  }
659
589
  };
660
590
 
661
591
  // src/modules/queries.ts
592
+ import {
593
+ createQueriesModule
594
+ } from "@mitralab.io/sdk-core";
662
595
  var QueriesModule = class {
663
- httpClient;
664
596
  dataSourceId = "";
597
+ core;
665
598
  constructor(httpClient) {
666
- this.httpClient = httpClient;
599
+ this.core = createQueriesModule(httpClient, () => this.dataSourceId, coreErrors);
667
600
  }
668
- /** @internal Called by client.init() to set the resolved data source. */
601
+ /** Called by `client.init()` to set the app's resolved data source. */
669
602
  setDataSourceId(dataSourceId) {
670
603
  this.dataSourceId = dataSourceId;
671
604
  }
672
- /**
673
- * Executes a named query.
674
- *
675
- * @param id - UUID of the custom query.
676
- * @param parameters - Named parameters for the prepared statement.
677
- * @returns Query result with rows and affected row count.
678
- * @throws {MitraApiError} On query not found (404).
679
- *
680
- * @example
681
- * ```typescript
682
- * const result = await mitra.queries.execute('query-id', { status: 'active' });
683
- * console.log(`Found ${result.rows.length} rows`);
684
- * ```
685
- */
686
605
  async execute(id, parameters) {
687
- return this.httpClient.post(
688
- `/api/v1/custom-queries/${id}/execute`,
689
- { datasourceId: this.dataSourceId, parameters }
690
- );
606
+ const result = await this.core.execute(id, parameters);
607
+ return { ...result, affectedRows: result.affectedRows ?? null };
691
608
  }
692
609
  };
693
610
 
694
611
  // src/client.ts
612
+ function expectAppInfoResponse(value) {
613
+ const response = expectObject(
614
+ value,
615
+ "App info response",
616
+ coreErrors
617
+ );
618
+ if (typeof response.dataSourceId !== "string" || !response.dataSourceId.trim()) {
619
+ throw coreErrors.invalidResponse(
620
+ "App info response has an invalid dataSourceId field"
621
+ );
622
+ }
623
+ if (typeof response.allowSignup !== "boolean") {
624
+ throw coreErrors.invalidResponse(
625
+ "App info response has an invalid allowSignup field"
626
+ );
627
+ }
628
+ return {
629
+ dataSourceId: response.dataSourceId,
630
+ allowSignup: response.allowSignup
631
+ };
632
+ }
695
633
  function createClient(config) {
696
634
  const { appId, apiUrl, onError } = config;
697
635
  const iamUrl = `${apiUrl}/iam`;
@@ -735,8 +673,10 @@ function createClient(config) {
735
673
  baseUrl: codeStudioUrl,
736
674
  getToken: () => null
737
675
  });
738
- const appInfo = await publicClient.get(
739
- `/api/v1/apps/${appId}/info`
676
+ const appInfo = expectAppInfoResponse(
677
+ await publicClient.get(
678
+ `/api/v1/apps/${encodePathSegment(appId, "appId", coreErrors)}/info`
679
+ )
740
680
  );
741
681
  entitiesModule.setDataSourceId(appInfo.dataSourceId);
742
682
  queriesModule.setDataSourceId(appInfo.dataSourceId);
@@ -756,8 +696,7 @@ function createClient(config) {
756
696
  config
757
697
  };
758
698
  }
759
- // Annotate the CommonJS export names for ESM import in node:
760
- 0 && (module.exports = {
699
+ export {
761
700
  MitraApiError,
762
701
  createClient
763
- });
702
+ };
package/package.json CHANGED
@@ -1,27 +1,46 @@
1
1
  {
2
2
  "name": "@mitralab.io/platform-sdk",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "JavaScript/TypeScript SDK for building apps on the Mitra Platform",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
8
10
  "exports": {
9
11
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.mjs",
12
- "require": "./dist/index.js"
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
13
20
  }
14
21
  },
15
22
  "files": [
16
- "dist"
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE",
26
+ "CHANGELOG.md"
17
27
  ],
28
+ "publishConfig": {
29
+ "access": "public",
30
+ "registry": "https://registry.npmjs.org"
31
+ },
18
32
  "scripts": {
19
33
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
20
34
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
21
35
  "lint": "eslint src --ext .ts",
22
- "test": "vitest run",
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "vitest run --coverage",
23
38
  "test:watch": "vitest",
24
- "prepublishOnly": "npm run build"
39
+ "check:package-types": "npx --yes @arethetypeswrong/cli@0.18.5 --pack .",
40
+ "pack:check": "npm pack --dry-run",
41
+ "smoke:package": "node scripts/smoke-package.mjs",
42
+ "check": "npm run lint && npm run typecheck && npm test && npm run build && npm run pack:check && npm run smoke:package",
43
+ "prepublishOnly": "npm run check && npm run check:package-types"
25
44
  },
26
45
  "keywords": [
27
46
  "mitra",
@@ -42,18 +61,27 @@
42
61
  "bugs": {
43
62
  "url": "https://github.com/mitralab-dev/mitra-platform-sdk/issues"
44
63
  },
64
+ "dependencies": {
65
+ "@mitralab.io/sdk-core": "^0.1.0"
66
+ },
45
67
  "devDependencies": {
46
- "@types/node": "^25.3.0",
47
- "@vitest/coverage-v8": "^4.1.2",
48
- "eslint": "^10.0.1",
49
- "tsup": "^8.0.1",
50
- "typescript": "^6.0.2",
51
- "vitest": "^4.1.2"
68
+ "@eslint/js": "^9.39.1",
69
+ "@types/node": "^22.15.0",
70
+ "@vitest/coverage-v8": "^3.2.4",
71
+ "eslint": "^9.39.1",
72
+ "globals": "^16.5.0",
73
+ "tsup": "^8.5.1",
74
+ "typescript": "~5.9.3",
75
+ "typescript-eslint": "~8.55.0",
76
+ "vite": "~6.4.3",
77
+ "vitest": "^3.2.4"
52
78
  },
53
79
  "engines": {
54
80
  "node": ">=18.0.0"
55
81
  },
56
82
  "overrides": {
57
- "rollup": "^4.59.0"
83
+ "esbuild": "^0.25.0",
84
+ "rollup": "^4.59.0",
85
+ "test-exclude": "7.0.1"
58
86
  }
59
87
  }