@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/CHANGELOG.md +17 -0
- package/LICENSE +21 -0
- package/README.md +110 -85
- package/dist/{index.mjs → index.cjs} +188 -201
- package/dist/{index.d.mts → index.d.cts} +37 -513
- package/dist/index.d.ts +37 -513
- package/dist/index.js +167 -228
- package/package.json +45 -17
package/dist/index.js
CHANGED
|
@@ -1,31 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
|
|
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
|
-
|
|
115
|
+
redactText(rawMessage || `Request failed with status ${response.status}`, token),
|
|
104
116
|
response.status,
|
|
105
|
-
|
|
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
|
-
|
|
192
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
241
|
-
this
|
|
242
|
-
const user = await this.
|
|
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
|
|
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
|
|
347
|
+
if (!this.#accessToken) return null;
|
|
327
348
|
try {
|
|
328
|
-
const user = await this.
|
|
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
|
|
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
|
|
441
|
+
{ refreshToken: this.#refreshToken }
|
|
421
442
|
);
|
|
422
|
-
this
|
|
423
|
-
this
|
|
424
|
-
const user = await this.
|
|
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
|
|
435
|
-
this
|
|
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
|
|
442
|
-
this
|
|
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
|
|
463
|
-
refreshToken: this
|
|
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
|
|
477
|
-
this
|
|
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.
|
|
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
|
|
505
|
-
if (
|
|
506
|
-
return target
|
|
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(
|
|
534
|
+
return target.getTable(property);
|
|
509
535
|
}
|
|
510
536
|
});
|
|
511
537
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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
|
-
|
|
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
|
-
|
|
555
|
+
core;
|
|
583
556
|
constructor(httpClient) {
|
|
584
|
-
this.
|
|
557
|
+
this.core = createFunctionsModule(httpClient, { emptyInput: "omit-body" }, coreErrors);
|
|
585
558
|
}
|
|
586
559
|
/**
|
|
587
|
-
* Executes a
|
|
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
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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
|
-
|
|
579
|
+
core;
|
|
613
580
|
constructor(httpClient) {
|
|
614
|
-
this.
|
|
581
|
+
this.core = createIntegrationModule(httpClient, coreErrors);
|
|
615
582
|
}
|
|
616
|
-
|
|
617
|
-
|
|
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
|
-
|
|
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.
|
|
599
|
+
this.core = createQueriesModule(httpClient, () => this.dataSourceId, coreErrors);
|
|
667
600
|
}
|
|
668
|
-
/**
|
|
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
|
-
|
|
688
|
-
|
|
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 =
|
|
739
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "JavaScript/TypeScript SDK for building apps on the Mitra Platform",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
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
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
"
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"test": "vitest run --coverage",
|
|
23
38
|
"test:watch": "vitest",
|
|
24
|
-
"
|
|
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
|
-
"@
|
|
47
|
-
"@
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
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
|
-
"
|
|
83
|
+
"esbuild": "^0.25.0",
|
|
84
|
+
"rollup": "^4.59.0",
|
|
85
|
+
"test-exclude": "7.0.1"
|
|
58
86
|
}
|
|
59
87
|
}
|