@mediaviz/sdk 1.2.0 → 1.4.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/dist/sdk.cjs +139 -48
- package/dist/sdk.d.cts +504 -0
- package/dist/sdk.d.ts +504 -0
- package/dist/sdk.esm.d.ts +504 -0
- package/dist/sdk.esm.js +139 -49
- package/dist/sdk.umd.js +139 -48
- package/package.json +10 -11
package/dist/sdk.cjs
CHANGED
|
@@ -91,8 +91,15 @@ function requireErrors () {
|
|
|
91
91
|
* @returns {OAuthError}
|
|
92
92
|
*/
|
|
93
93
|
static fromResponse(status, body) {
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
// FastAPI wraps HTTPException payloads in a `detail` envelope, so an OAuth
|
|
95
|
+
// error arrives as { detail: { error, error_description } }. Unwrap it
|
|
96
|
+
// before falling back, or every server-side OAuth error reads as server_error.
|
|
97
|
+
const payload =
|
|
98
|
+
body && typeof body === 'object' && typeof body.error !== 'string' && body.detail
|
|
99
|
+
? body.detail
|
|
100
|
+
: body;
|
|
101
|
+
if (payload && typeof payload === 'object' && typeof payload.error === 'string') {
|
|
102
|
+
return new OAuthError(payload.error, payload.error_description ?? '', status, body);
|
|
96
103
|
}
|
|
97
104
|
return new OAuthError('server_error', 'Unexpected server response', status, body);
|
|
98
105
|
}
|
|
@@ -173,6 +180,9 @@ function requireClient () {
|
|
|
173
180
|
const { postForm, postJson } = requireHttp();
|
|
174
181
|
const { OAuthError } = requireErrors();
|
|
175
182
|
|
|
183
|
+
// In-flight dedup key for client_credentials re-mints (no refresh_token to key on).
|
|
184
|
+
const CLIENT_CREDENTIALS_KEY = Symbol('client_credentials');
|
|
185
|
+
|
|
176
186
|
class OAuthClient {
|
|
177
187
|
/**
|
|
178
188
|
* @param {import('./types').OAuthClientConfig} config
|
|
@@ -188,12 +198,22 @@ function requireClient () {
|
|
|
188
198
|
*/
|
|
189
199
|
static async registerClient(params) {
|
|
190
200
|
const baseUrl = params.baseUrl.replace(/\/+$/, '');
|
|
191
|
-
|
|
201
|
+
const body = {
|
|
192
202
|
client_name: params.clientName,
|
|
193
203
|
client_type: params.clientType,
|
|
194
204
|
redirect_uris: params.redirectUris,
|
|
195
205
|
is_first_party: params.isFirstParty,
|
|
196
|
-
}
|
|
206
|
+
};
|
|
207
|
+
// grant_types/company_id are required to provision a confidential
|
|
208
|
+
// client_credentials (machine-to-machine) client; omitted bodies keep the
|
|
209
|
+
// legacy public/authorization_code shape. The endpoint is admin-gated, so a
|
|
210
|
+
// bearer token must be supplied for the request to authenticate.
|
|
211
|
+
if (params.grantTypes !== undefined) body.grant_types = params.grantTypes;
|
|
212
|
+
if (params.companyId !== undefined) body.company_id = params.companyId;
|
|
213
|
+
const headers = params.accessToken
|
|
214
|
+
? { Authorization: `Bearer ${params.accessToken}` }
|
|
215
|
+
: {};
|
|
216
|
+
return postJson(`${baseUrl}/oauth/clients`, body, headers);
|
|
197
217
|
}
|
|
198
218
|
|
|
199
219
|
/**
|
|
@@ -311,15 +331,27 @@ function requireClient () {
|
|
|
311
331
|
return { data: json, updatedTokens: null };
|
|
312
332
|
}
|
|
313
333
|
|
|
314
|
-
// 401:
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
|
|
334
|
+
// 401: re-authenticate, then retry once.
|
|
335
|
+
// - User sessions (refresh_token present) use the refresh_token grant. The server
|
|
336
|
+
// rotates the token one-time, so concurrent callers share one in-flight call
|
|
337
|
+
// (a second rotation would get invalid_grant).
|
|
338
|
+
// - Machine-to-machine sessions (no refresh_token, client_secret configured) re-mint
|
|
339
|
+
// via client_credentials, which issues no refresh token to rotate (RFC 6749 §4.4).
|
|
340
|
+
// - With neither a refresh_token nor a client_secret there is nothing to retry with.
|
|
341
|
+
if (!refreshToken && !this._config.clientSecret) {
|
|
342
|
+
throw OAuthError.fromResponse(401, await firstResponse.json());
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const reauthKey = refreshToken || CLIENT_CREDENTIALS_KEY;
|
|
346
|
+
let pending = this._inFlightRefreshes.get(reauthKey);
|
|
318
347
|
if (!pending) {
|
|
319
|
-
|
|
320
|
-
this.
|
|
348
|
+
const reauth = refreshToken
|
|
349
|
+
? this.refreshAccessToken(refreshToken)
|
|
350
|
+
: this.getClientCredentialsToken();
|
|
351
|
+
pending = reauth.finally(() => {
|
|
352
|
+
this._inFlightRefreshes.delete(reauthKey);
|
|
321
353
|
});
|
|
322
|
-
this._inFlightRefreshes.set(
|
|
354
|
+
this._inFlightRefreshes.set(reauthKey, pending);
|
|
323
355
|
}
|
|
324
356
|
const newTokens = await pending;
|
|
325
357
|
|
|
@@ -401,6 +433,9 @@ function requireTypes () {
|
|
|
401
433
|
* @property {string} clientType - "public" or "confidential"
|
|
402
434
|
* @property {string[]} redirectUris - HTTPS redirect URIs
|
|
403
435
|
* @property {boolean} isFirstParty - Whether this is a first-party client
|
|
436
|
+
* @property {string[]} [grantTypes] - Allowed grants, e.g. ["client_credentials"]; required for machine-to-machine clients
|
|
437
|
+
* @property {number} [companyId] - Company to bind the client to; required for the client_credentials grant
|
|
438
|
+
* @property {string} [accessToken] - Admin bearer token; the registration endpoint is authorization-gated
|
|
404
439
|
*/
|
|
405
440
|
|
|
406
441
|
/**
|
|
@@ -458,6 +493,17 @@ class AiModelCredits {
|
|
|
458
493
|
}
|
|
459
494
|
}
|
|
460
495
|
|
|
496
|
+
class Admin {
|
|
497
|
+
constructor(ctx) { this._ctx = ctx; }
|
|
498
|
+
|
|
499
|
+
async getCategoryLabels(category) {
|
|
500
|
+
this._ctx.requireTokens();
|
|
501
|
+
const path = `/api/v1/admin/category_labels/${encodeURIComponent(category)}`;
|
|
502
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
503
|
+
return data;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
461
507
|
class Company {
|
|
462
508
|
constructor(ctx) { this._ctx = ctx; }
|
|
463
509
|
|
|
@@ -901,6 +947,17 @@ class Keywords {
|
|
|
901
947
|
return data;
|
|
902
948
|
}
|
|
903
949
|
|
|
950
|
+
async addCompanyToKeywordFilteringList(keywordListId, { companyId } = {}) {
|
|
951
|
+
this._ctx.requireTokens();
|
|
952
|
+
let path = `/api/v1/keyword/${encodeURIComponent(keywordListId)}/company`;
|
|
953
|
+
const query = new URLSearchParams();
|
|
954
|
+
if (companyId !== undefined) (Array.isArray(companyId) ? companyId : [companyId]).forEach(v => query.append('company_id', v));
|
|
955
|
+
const qs = query.toString();
|
|
956
|
+
if (qs) path += '?' + qs;
|
|
957
|
+
const { data } = await this._ctx.client.request(path, 'POST', this._ctx.accessToken, this._ctx.refreshToken);
|
|
958
|
+
return data;
|
|
959
|
+
}
|
|
960
|
+
|
|
904
961
|
async requestKeywordListExport(keywordListId) {
|
|
905
962
|
this._ctx.requireTokens();
|
|
906
963
|
const path = `/api/v1/keyword/export/${encodeURIComponent(keywordListId)}`;
|
|
@@ -933,6 +990,17 @@ class Keywords {
|
|
|
933
990
|
return data;
|
|
934
991
|
}
|
|
935
992
|
|
|
993
|
+
async removeCompanyFromKeywordFilteringList(keywordListId, { companyId } = {}) {
|
|
994
|
+
this._ctx.requireTokens();
|
|
995
|
+
let path = `/api/v1/keyword/${encodeURIComponent(keywordListId)}/company`;
|
|
996
|
+
const query = new URLSearchParams();
|
|
997
|
+
if (companyId !== undefined) (Array.isArray(companyId) ? companyId : [companyId]).forEach(v => query.append('company_id', v));
|
|
998
|
+
const qs = query.toString();
|
|
999
|
+
if (qs) path += '?' + qs;
|
|
1000
|
+
const { data } = await this._ctx.client.request(path, 'DELETE', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1001
|
+
return data;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
936
1004
|
async deleteKeywordFilteringListById(keywordListId) {
|
|
937
1005
|
this._ctx.requireTokens();
|
|
938
1006
|
const path = `/api/v1/keyword/${encodeURIComponent(keywordListId)}`;
|
|
@@ -1092,6 +1160,17 @@ class Person {
|
|
|
1092
1160
|
return data;
|
|
1093
1161
|
}
|
|
1094
1162
|
|
|
1163
|
+
async getPhotoIdsByPersons(projectTableName, { personId } = {}) {
|
|
1164
|
+
this._ctx.requireTokens();
|
|
1165
|
+
let path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photos`;
|
|
1166
|
+
const query = new URLSearchParams();
|
|
1167
|
+
if (personId !== undefined) (Array.isArray(personId) ? personId : [personId]).forEach(v => query.append('person_id', v));
|
|
1168
|
+
const qs = query.toString();
|
|
1169
|
+
if (qs) path += '?' + qs;
|
|
1170
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1171
|
+
return data;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1095
1174
|
async getAllPersonsFromPhoto(projectTableName, photoId) {
|
|
1096
1175
|
this._ctx.requireTokens();
|
|
1097
1176
|
const path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photo/${encodeURIComponent(photoId)}`;
|
|
@@ -1392,13 +1471,6 @@ class Photos {
|
|
|
1392
1471
|
return data;
|
|
1393
1472
|
}
|
|
1394
1473
|
|
|
1395
|
-
async getProjectThumbnail(tableName) {
|
|
1396
|
-
this._ctx.requireTokens();
|
|
1397
|
-
const path = `/api/v1/photos_project/${encodeURIComponent(tableName)}`;
|
|
1398
|
-
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1399
|
-
return data;
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
1474
|
async updatePhotoInProject({ tableName, photoId, photoData } = {}) {
|
|
1403
1475
|
this._ctx.requireTokens();
|
|
1404
1476
|
let path = `/api/v1/photos_update`;
|
|
@@ -1461,50 +1533,56 @@ class Search {
|
|
|
1461
1533
|
return data;
|
|
1462
1534
|
}
|
|
1463
1535
|
|
|
1464
|
-
async
|
|
1536
|
+
async searchProjectPhotosParametrized(projectTableName, { andSearchText, orSearchText, notSearchText, city, country, state, albums, dateMin, dateMax, dateNullAnd, dateNullOr, ascOrDesc, bestOfSimilarSetsOnly, splitByTier, lastId, limit } = {}) {
|
|
1465
1537
|
this._ctx.requireTokens();
|
|
1466
|
-
|
|
1467
|
-
const
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1538
|
+
let path = `/api/v1/search/parametrized/${encodeURIComponent(projectTableName)}/`;
|
|
1539
|
+
const query = new URLSearchParams();
|
|
1540
|
+
if (andSearchText !== undefined) (Array.isArray(andSearchText) ? andSearchText : [andSearchText]).forEach(v => query.append('and_search_text', v));
|
|
1541
|
+
if (orSearchText !== undefined) (Array.isArray(orSearchText) ? orSearchText : [orSearchText]).forEach(v => query.append('or_search_text', v));
|
|
1542
|
+
if (notSearchText !== undefined) (Array.isArray(notSearchText) ? notSearchText : [notSearchText]).forEach(v => query.append('not_search_text', v));
|
|
1543
|
+
if (city !== undefined) (Array.isArray(city) ? city : [city]).forEach(v => query.append('city', v));
|
|
1544
|
+
if (country !== undefined) (Array.isArray(country) ? country : [country]).forEach(v => query.append('country', v));
|
|
1545
|
+
if (state !== undefined) (Array.isArray(state) ? state : [state]).forEach(v => query.append('state', v));
|
|
1546
|
+
if (albums !== undefined) (Array.isArray(albums) ? albums : [albums]).forEach(v => query.append('albums', v));
|
|
1547
|
+
if (dateMin !== undefined) (Array.isArray(dateMin) ? dateMin : [dateMin]).forEach(v => query.append('date_min', v));
|
|
1548
|
+
if (dateMax !== undefined) (Array.isArray(dateMax) ? dateMax : [dateMax]).forEach(v => query.append('date_max', v));
|
|
1549
|
+
if (dateNullAnd !== undefined) (Array.isArray(dateNullAnd) ? dateNullAnd : [dateNullAnd]).forEach(v => query.append('date_null_and', v));
|
|
1550
|
+
if (dateNullOr !== undefined) (Array.isArray(dateNullOr) ? dateNullOr : [dateNullOr]).forEach(v => query.append('date_null_or', v));
|
|
1551
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1552
|
+
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1553
|
+
if (splitByTier !== undefined) (Array.isArray(splitByTier) ? splitByTier : [splitByTier]).forEach(v => query.append('split_by_tier', v));
|
|
1554
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1555
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1556
|
+
const qs = query.toString();
|
|
1557
|
+
if (qs) path += '?' + qs;
|
|
1558
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1483
1559
|
return data;
|
|
1484
1560
|
}
|
|
1485
1561
|
|
|
1486
|
-
async
|
|
1562
|
+
async recallProjectPhotoIds(projectTableName, { ascOrDesc, bestOfSimilarSetsOnly, lastId, limit } = {}) {
|
|
1487
1563
|
this._ctx.requireTokens();
|
|
1488
|
-
let path = `/api/v1/search/
|
|
1564
|
+
let path = `/api/v1/search/recall/${encodeURIComponent(projectTableName)}/`;
|
|
1489
1565
|
const query = new URLSearchParams();
|
|
1490
|
-
if (
|
|
1491
|
-
if (
|
|
1566
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1567
|
+
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1568
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1569
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1492
1570
|
const qs = query.toString();
|
|
1493
1571
|
if (qs) path += '?' + qs;
|
|
1494
|
-
const
|
|
1495
|
-
search_text: searchText,
|
|
1496
|
-
size: size,
|
|
1497
|
-
});
|
|
1498
|
-
const { data } = await this._ctx.client.request(path, 'POST', this._ctx.accessToken, this._ctx.refreshToken, body);
|
|
1572
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1499
1573
|
return data;
|
|
1500
1574
|
}
|
|
1501
1575
|
|
|
1502
|
-
async
|
|
1576
|
+
async searchProjectPhotosNaturalLanguage(projectTableName, searchText, size = undefined, { minCosine, labelMinCosine, labelTopK, labelDelta, bestOfSimilarSetsOnly, splitByTier } = {}) {
|
|
1503
1577
|
this._ctx.requireTokens();
|
|
1504
|
-
let path = `/api/v1/search/
|
|
1578
|
+
let path = `/api/v1/search/natural_language/${encodeURIComponent(projectTableName)}/`;
|
|
1505
1579
|
const query = new URLSearchParams();
|
|
1506
|
-
if (blend !== undefined) (Array.isArray(blend) ? blend : [blend]).forEach(v => query.append('blend', v));
|
|
1507
1580
|
if (minCosine !== undefined) (Array.isArray(minCosine) ? minCosine : [minCosine]).forEach(v => query.append('min_cosine', v));
|
|
1581
|
+
if (labelMinCosine !== undefined) (Array.isArray(labelMinCosine) ? labelMinCosine : [labelMinCosine]).forEach(v => query.append('label_min_cosine', v));
|
|
1582
|
+
if (labelTopK !== undefined) (Array.isArray(labelTopK) ? labelTopK : [labelTopK]).forEach(v => query.append('label_top_k', v));
|
|
1583
|
+
if (labelDelta !== undefined) (Array.isArray(labelDelta) ? labelDelta : [labelDelta]).forEach(v => query.append('label_delta', v));
|
|
1584
|
+
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1585
|
+
if (splitByTier !== undefined) (Array.isArray(splitByTier) ? splitByTier : [splitByTier]).forEach(v => query.append('split_by_tier', v));
|
|
1508
1586
|
const qs = query.toString();
|
|
1509
1587
|
if (qs) path += '?' + qs;
|
|
1510
1588
|
const body = stripUndef$1({
|
|
@@ -1656,6 +1734,17 @@ class Users {
|
|
|
1656
1734
|
const { data } = await this._ctx.client.request(path, 'PUT', this._ctx.accessToken, this._ctx.refreshToken, body);
|
|
1657
1735
|
return data;
|
|
1658
1736
|
}
|
|
1737
|
+
|
|
1738
|
+
async deleteUser(userId, { newCompanyOwnerId } = {}) {
|
|
1739
|
+
this._ctx.requireTokens();
|
|
1740
|
+
let path = `/api/v1/users/delete/${encodeURIComponent(userId)}`;
|
|
1741
|
+
const query = new URLSearchParams();
|
|
1742
|
+
if (newCompanyOwnerId !== undefined) (Array.isArray(newCompanyOwnerId) ? newCompanyOwnerId : [newCompanyOwnerId]).forEach(v => query.append('new_company_owner_id', v));
|
|
1743
|
+
const qs = query.toString();
|
|
1744
|
+
if (qs) path += '?' + qs;
|
|
1745
|
+
const { data } = await this._ctx.client.request(path, 'DELETE', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1746
|
+
return data;
|
|
1747
|
+
}
|
|
1659
1748
|
}
|
|
1660
1749
|
|
|
1661
1750
|
// Auto-generated — do not edit
|
|
@@ -1720,6 +1809,7 @@ class MediaViz {
|
|
|
1720
1809
|
|
|
1721
1810
|
const _ctx = new _Context(this);
|
|
1722
1811
|
this.aiModelCredits = new AiModelCredits(_ctx);
|
|
1812
|
+
this.admin = new Admin(_ctx);
|
|
1723
1813
|
this.company = new Company(_ctx);
|
|
1724
1814
|
this.curatedAlbums = new CuratedAlbums(_ctx);
|
|
1725
1815
|
this.customAlbums = new CustomAlbums(_ctx);
|
|
@@ -1764,6 +1854,7 @@ class MediaViz {
|
|
|
1764
1854
|
get refreshToken() { return this._refreshToken; }
|
|
1765
1855
|
}
|
|
1766
1856
|
|
|
1857
|
+
exports.Admin = Admin;
|
|
1767
1858
|
exports.AiModelCredits = AiModelCredits;
|
|
1768
1859
|
exports.ApiError = ApiError;
|
|
1769
1860
|
exports.Company = Company;
|