@mediaviz/sdk 1.0.78 → 1.0.80
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 +51 -10
- package/dist/sdk.d.cts +3 -1
- package/dist/sdk.d.ts +3 -1
- package/dist/sdk.esm.d.ts +3 -1
- package/dist/sdk.esm.js +51 -10
- package/dist/sdk.umd.js +51 -10
- package/package.json +1 -1
package/dist/sdk.cjs
CHANGED
|
@@ -173,6 +173,9 @@ function requireClient () {
|
|
|
173
173
|
const { postForm, postJson } = requireHttp();
|
|
174
174
|
const { OAuthError } = requireErrors();
|
|
175
175
|
|
|
176
|
+
// In-flight dedup key for client_credentials re-mints (no refresh_token to key on).
|
|
177
|
+
const CLIENT_CREDENTIALS_KEY = Symbol('client_credentials');
|
|
178
|
+
|
|
176
179
|
class OAuthClient {
|
|
177
180
|
/**
|
|
178
181
|
* @param {import('./types').OAuthClientConfig} config
|
|
@@ -311,15 +314,27 @@ function requireClient () {
|
|
|
311
314
|
return { data: json, updatedTokens: null };
|
|
312
315
|
}
|
|
313
316
|
|
|
314
|
-
// 401:
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
|
|
317
|
+
// 401: re-authenticate, then retry once.
|
|
318
|
+
// - User sessions (refresh_token present) use the refresh_token grant. The server
|
|
319
|
+
// rotates the token one-time, so concurrent callers share one in-flight call
|
|
320
|
+
// (a second rotation would get invalid_grant).
|
|
321
|
+
// - Machine-to-machine sessions (no refresh_token, client_secret configured) re-mint
|
|
322
|
+
// via client_credentials, which issues no refresh token to rotate (RFC 6749 §4.4).
|
|
323
|
+
// - With neither a refresh_token nor a client_secret there is nothing to retry with.
|
|
324
|
+
if (!refreshToken && !this._config.clientSecret) {
|
|
325
|
+
throw OAuthError.fromResponse(401, await firstResponse.json());
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const reauthKey = refreshToken || CLIENT_CREDENTIALS_KEY;
|
|
329
|
+
let pending = this._inFlightRefreshes.get(reauthKey);
|
|
318
330
|
if (!pending) {
|
|
319
|
-
|
|
320
|
-
this.
|
|
331
|
+
const reauth = refreshToken
|
|
332
|
+
? this.refreshAccessToken(refreshToken)
|
|
333
|
+
: this.getClientCredentialsToken();
|
|
334
|
+
pending = reauth.finally(() => {
|
|
335
|
+
this._inFlightRefreshes.delete(reauthKey);
|
|
321
336
|
});
|
|
322
|
-
this._inFlightRefreshes.set(
|
|
337
|
+
this._inFlightRefreshes.set(reauthKey, pending);
|
|
323
338
|
}
|
|
324
339
|
const newTokens = await pending;
|
|
325
340
|
|
|
@@ -1125,6 +1140,17 @@ class Person {
|
|
|
1125
1140
|
return data;
|
|
1126
1141
|
}
|
|
1127
1142
|
|
|
1143
|
+
async getPhotoIdsByPersons(projectTableName, { personId } = {}) {
|
|
1144
|
+
this._ctx.requireTokens();
|
|
1145
|
+
let path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photos`;
|
|
1146
|
+
const query = new URLSearchParams();
|
|
1147
|
+
if (personId !== undefined) (Array.isArray(personId) ? personId : [personId]).forEach(v => query.append('person_id', v));
|
|
1148
|
+
const qs = query.toString();
|
|
1149
|
+
if (qs) path += '?' + qs;
|
|
1150
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1151
|
+
return data;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1128
1154
|
async getAllPersonsFromPhoto(projectTableName, photoId) {
|
|
1129
1155
|
this._ctx.requireTokens();
|
|
1130
1156
|
const path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photo/${encodeURIComponent(photoId)}`;
|
|
@@ -1487,7 +1513,7 @@ class Search {
|
|
|
1487
1513
|
return data;
|
|
1488
1514
|
}
|
|
1489
1515
|
|
|
1490
|
-
async searchProjectPhotosParametrized(projectTableName, { andSearchText, orSearchText, notSearchText, city, country, state, albums, dateMin, dateMax, dateNullAnd, dateNullOr,
|
|
1516
|
+
async searchProjectPhotosParametrized(projectTableName, { andSearchText, orSearchText, notSearchText, city, country, state, albums, dateMin, dateMax, dateNullAnd, dateNullOr, ascOrDesc, bestOfSimilarSetsOnly, splitByTier, lastId, limit } = {}) {
|
|
1491
1517
|
this._ctx.requireTokens();
|
|
1492
1518
|
let path = `/api/v1/search/parametrized/${encodeURIComponent(projectTableName)}/`;
|
|
1493
1519
|
const query = new URLSearchParams();
|
|
@@ -1502,10 +1528,25 @@ class Search {
|
|
|
1502
1528
|
if (dateMax !== undefined) (Array.isArray(dateMax) ? dateMax : [dateMax]).forEach(v => query.append('date_max', v));
|
|
1503
1529
|
if (dateNullAnd !== undefined) (Array.isArray(dateNullAnd) ? dateNullAnd : [dateNullAnd]).forEach(v => query.append('date_null_and', v));
|
|
1504
1530
|
if (dateNullOr !== undefined) (Array.isArray(dateNullOr) ? dateNullOr : [dateNullOr]).forEach(v => query.append('date_null_or', v));
|
|
1505
|
-
if (
|
|
1531
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1506
1532
|
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1507
1533
|
if (splitByTier !== undefined) (Array.isArray(splitByTier) ? splitByTier : [splitByTier]).forEach(v => query.append('split_by_tier', v));
|
|
1508
|
-
if (
|
|
1534
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1535
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1536
|
+
const qs = query.toString();
|
|
1537
|
+
if (qs) path += '?' + qs;
|
|
1538
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1539
|
+
return data;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
async recallProjectPhotoIds(projectTableName, { ascOrDesc, bestOfSimilarSetsOnly, lastId, limit } = {}) {
|
|
1543
|
+
this._ctx.requireTokens();
|
|
1544
|
+
let path = `/api/v1/search/recall/${encodeURIComponent(projectTableName)}/`;
|
|
1545
|
+
const query = new URLSearchParams();
|
|
1546
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1547
|
+
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1548
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1549
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1509
1550
|
const qs = query.toString();
|
|
1510
1551
|
if (qs) path += '?' + qs;
|
|
1511
1552
|
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
package/dist/sdk.d.cts
CHANGED
|
@@ -411,6 +411,7 @@ export class Person {
|
|
|
411
411
|
splitPersons(projectTableName: string, id: number, options?: { newName?: string | string[], destinationPersonId?: string | string[] }): Promise<PhotoPersonLight>;
|
|
412
412
|
getAllPersonsFromProject(projectTableName: string): Promise<PhotoPersonWithS3Link[]>;
|
|
413
413
|
getAllPersonNamesFromProject(projectTableName: string): Promise<any>;
|
|
414
|
+
getPhotoIdsByPersons(projectTableName: string, options?: { personId?: string[] | string[][] }): Promise<any>;
|
|
414
415
|
getAllPersonsFromPhoto(projectTableName: string, photoId: number): Promise<PhotoPersonLight[]>;
|
|
415
416
|
}
|
|
416
417
|
|
|
@@ -454,7 +455,8 @@ export class Projects {
|
|
|
454
455
|
|
|
455
456
|
export class Search {
|
|
456
457
|
searchProjectPhotos(projectTableName: string, options?: { andParams?: any, andStringParams?: any, orParams?: any, orStringParams?: any, notParams?: any, notStringParams?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[], dateOrder?: string | string[], customAlbumId?: number | number[], bestOfSimilarSetsOnly?: boolean | boolean[], curatedAlbumId?: number | number[], splitByTier?: boolean | boolean[] }): Promise<Record<string, any>>;
|
|
457
|
-
searchProjectPhotosParametrized(projectTableName: string, options?: { andSearchText?: any, orSearchText?: any, notSearchText?: any, city?: any, country?: any, state?: any, albums?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[],
|
|
458
|
+
searchProjectPhotosParametrized(projectTableName: string, options?: { andSearchText?: any, orSearchText?: any, notSearchText?: any, city?: any, country?: any, state?: any, albums?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[], ascOrDesc?: string | string[], bestOfSimilarSetsOnly?: boolean | boolean[], splitByTier?: boolean | boolean[], lastId?: number | number[], limit?: number | number[] }): Promise<Record<string, any>>;
|
|
459
|
+
recallProjectPhotoIds(projectTableName: string, options?: { ascOrDesc?: string | string[], bestOfSimilarSetsOnly?: boolean | boolean[], lastId?: number | number[], limit?: number | number[] }): Promise<any>;
|
|
458
460
|
searchProjectPhotosNaturalLanguage(projectTableName: string, searchText: string, size?: number, options?: { minCosine?: number | number[], labelMinCosine?: number | number[], labelTopK?: number | number[], labelDelta?: number | number[], bestOfSimilarSetsOnly?: boolean | boolean[], splitByTier?: boolean | boolean[] }): Promise<Record<string, any>>;
|
|
459
461
|
getProjectSavedSearches(projectTableName: string): Promise<any>;
|
|
460
462
|
getSavedSearchById(searchId: number): Promise<SearchDisplay>;
|
package/dist/sdk.d.ts
CHANGED
|
@@ -411,6 +411,7 @@ export class Person {
|
|
|
411
411
|
splitPersons(projectTableName: string, id: number, options?: { newName?: string | string[], destinationPersonId?: string | string[] }): Promise<PhotoPersonLight>;
|
|
412
412
|
getAllPersonsFromProject(projectTableName: string): Promise<PhotoPersonWithS3Link[]>;
|
|
413
413
|
getAllPersonNamesFromProject(projectTableName: string): Promise<any>;
|
|
414
|
+
getPhotoIdsByPersons(projectTableName: string, options?: { personId?: string[] | string[][] }): Promise<any>;
|
|
414
415
|
getAllPersonsFromPhoto(projectTableName: string, photoId: number): Promise<PhotoPersonLight[]>;
|
|
415
416
|
}
|
|
416
417
|
|
|
@@ -454,7 +455,8 @@ export class Projects {
|
|
|
454
455
|
|
|
455
456
|
export class Search {
|
|
456
457
|
searchProjectPhotos(projectTableName: string, options?: { andParams?: any, andStringParams?: any, orParams?: any, orStringParams?: any, notParams?: any, notStringParams?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[], dateOrder?: string | string[], customAlbumId?: number | number[], bestOfSimilarSetsOnly?: boolean | boolean[], curatedAlbumId?: number | number[], splitByTier?: boolean | boolean[] }): Promise<Record<string, any>>;
|
|
457
|
-
searchProjectPhotosParametrized(projectTableName: string, options?: { andSearchText?: any, orSearchText?: any, notSearchText?: any, city?: any, country?: any, state?: any, albums?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[],
|
|
458
|
+
searchProjectPhotosParametrized(projectTableName: string, options?: { andSearchText?: any, orSearchText?: any, notSearchText?: any, city?: any, country?: any, state?: any, albums?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[], ascOrDesc?: string | string[], bestOfSimilarSetsOnly?: boolean | boolean[], splitByTier?: boolean | boolean[], lastId?: number | number[], limit?: number | number[] }): Promise<Record<string, any>>;
|
|
459
|
+
recallProjectPhotoIds(projectTableName: string, options?: { ascOrDesc?: string | string[], bestOfSimilarSetsOnly?: boolean | boolean[], lastId?: number | number[], limit?: number | number[] }): Promise<any>;
|
|
458
460
|
searchProjectPhotosNaturalLanguage(projectTableName: string, searchText: string, size?: number, options?: { minCosine?: number | number[], labelMinCosine?: number | number[], labelTopK?: number | number[], labelDelta?: number | number[], bestOfSimilarSetsOnly?: boolean | boolean[], splitByTier?: boolean | boolean[] }): Promise<Record<string, any>>;
|
|
459
461
|
getProjectSavedSearches(projectTableName: string): Promise<any>;
|
|
460
462
|
getSavedSearchById(searchId: number): Promise<SearchDisplay>;
|
package/dist/sdk.esm.d.ts
CHANGED
|
@@ -411,6 +411,7 @@ export class Person {
|
|
|
411
411
|
splitPersons(projectTableName: string, id: number, options?: { newName?: string | string[], destinationPersonId?: string | string[] }): Promise<PhotoPersonLight>;
|
|
412
412
|
getAllPersonsFromProject(projectTableName: string): Promise<PhotoPersonWithS3Link[]>;
|
|
413
413
|
getAllPersonNamesFromProject(projectTableName: string): Promise<any>;
|
|
414
|
+
getPhotoIdsByPersons(projectTableName: string, options?: { personId?: string[] | string[][] }): Promise<any>;
|
|
414
415
|
getAllPersonsFromPhoto(projectTableName: string, photoId: number): Promise<PhotoPersonLight[]>;
|
|
415
416
|
}
|
|
416
417
|
|
|
@@ -454,7 +455,8 @@ export class Projects {
|
|
|
454
455
|
|
|
455
456
|
export class Search {
|
|
456
457
|
searchProjectPhotos(projectTableName: string, options?: { andParams?: any, andStringParams?: any, orParams?: any, orStringParams?: any, notParams?: any, notStringParams?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[], dateOrder?: string | string[], customAlbumId?: number | number[], bestOfSimilarSetsOnly?: boolean | boolean[], curatedAlbumId?: number | number[], splitByTier?: boolean | boolean[] }): Promise<Record<string, any>>;
|
|
457
|
-
searchProjectPhotosParametrized(projectTableName: string, options?: { andSearchText?: any, orSearchText?: any, notSearchText?: any, city?: any, country?: any, state?: any, albums?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[],
|
|
458
|
+
searchProjectPhotosParametrized(projectTableName: string, options?: { andSearchText?: any, orSearchText?: any, notSearchText?: any, city?: any, country?: any, state?: any, albums?: any, dateMin?: string | string[], dateMax?: string | string[], dateNullAnd?: boolean | boolean[], dateNullOr?: boolean | boolean[], ascOrDesc?: string | string[], bestOfSimilarSetsOnly?: boolean | boolean[], splitByTier?: boolean | boolean[], lastId?: number | number[], limit?: number | number[] }): Promise<Record<string, any>>;
|
|
459
|
+
recallProjectPhotoIds(projectTableName: string, options?: { ascOrDesc?: string | string[], bestOfSimilarSetsOnly?: boolean | boolean[], lastId?: number | number[], limit?: number | number[] }): Promise<any>;
|
|
458
460
|
searchProjectPhotosNaturalLanguage(projectTableName: string, searchText: string, size?: number, options?: { minCosine?: number | number[], labelMinCosine?: number | number[], labelTopK?: number | number[], labelDelta?: number | number[], bestOfSimilarSetsOnly?: boolean | boolean[], splitByTier?: boolean | boolean[] }): Promise<Record<string, any>>;
|
|
459
461
|
getProjectSavedSearches(projectTableName: string): Promise<any>;
|
|
460
462
|
getSavedSearchById(searchId: number): Promise<SearchDisplay>;
|
package/dist/sdk.esm.js
CHANGED
|
@@ -171,6 +171,9 @@ function requireClient () {
|
|
|
171
171
|
const { postForm, postJson } = requireHttp();
|
|
172
172
|
const { OAuthError } = requireErrors();
|
|
173
173
|
|
|
174
|
+
// In-flight dedup key for client_credentials re-mints (no refresh_token to key on).
|
|
175
|
+
const CLIENT_CREDENTIALS_KEY = Symbol('client_credentials');
|
|
176
|
+
|
|
174
177
|
class OAuthClient {
|
|
175
178
|
/**
|
|
176
179
|
* @param {import('./types').OAuthClientConfig} config
|
|
@@ -309,15 +312,27 @@ function requireClient () {
|
|
|
309
312
|
return { data: json, updatedTokens: null };
|
|
310
313
|
}
|
|
311
314
|
|
|
312
|
-
// 401:
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
|
|
315
|
+
// 401: re-authenticate, then retry once.
|
|
316
|
+
// - User sessions (refresh_token present) use the refresh_token grant. The server
|
|
317
|
+
// rotates the token one-time, so concurrent callers share one in-flight call
|
|
318
|
+
// (a second rotation would get invalid_grant).
|
|
319
|
+
// - Machine-to-machine sessions (no refresh_token, client_secret configured) re-mint
|
|
320
|
+
// via client_credentials, which issues no refresh token to rotate (RFC 6749 §4.4).
|
|
321
|
+
// - With neither a refresh_token nor a client_secret there is nothing to retry with.
|
|
322
|
+
if (!refreshToken && !this._config.clientSecret) {
|
|
323
|
+
throw OAuthError.fromResponse(401, await firstResponse.json());
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const reauthKey = refreshToken || CLIENT_CREDENTIALS_KEY;
|
|
327
|
+
let pending = this._inFlightRefreshes.get(reauthKey);
|
|
316
328
|
if (!pending) {
|
|
317
|
-
|
|
318
|
-
this.
|
|
329
|
+
const reauth = refreshToken
|
|
330
|
+
? this.refreshAccessToken(refreshToken)
|
|
331
|
+
: this.getClientCredentialsToken();
|
|
332
|
+
pending = reauth.finally(() => {
|
|
333
|
+
this._inFlightRefreshes.delete(reauthKey);
|
|
319
334
|
});
|
|
320
|
-
this._inFlightRefreshes.set(
|
|
335
|
+
this._inFlightRefreshes.set(reauthKey, pending);
|
|
321
336
|
}
|
|
322
337
|
const newTokens = await pending;
|
|
323
338
|
|
|
@@ -1123,6 +1138,17 @@ class Person {
|
|
|
1123
1138
|
return data;
|
|
1124
1139
|
}
|
|
1125
1140
|
|
|
1141
|
+
async getPhotoIdsByPersons(projectTableName, { personId } = {}) {
|
|
1142
|
+
this._ctx.requireTokens();
|
|
1143
|
+
let path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photos`;
|
|
1144
|
+
const query = new URLSearchParams();
|
|
1145
|
+
if (personId !== undefined) (Array.isArray(personId) ? personId : [personId]).forEach(v => query.append('person_id', v));
|
|
1146
|
+
const qs = query.toString();
|
|
1147
|
+
if (qs) path += '?' + qs;
|
|
1148
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1149
|
+
return data;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1126
1152
|
async getAllPersonsFromPhoto(projectTableName, photoId) {
|
|
1127
1153
|
this._ctx.requireTokens();
|
|
1128
1154
|
const path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photo/${encodeURIComponent(photoId)}`;
|
|
@@ -1485,7 +1511,7 @@ class Search {
|
|
|
1485
1511
|
return data;
|
|
1486
1512
|
}
|
|
1487
1513
|
|
|
1488
|
-
async searchProjectPhotosParametrized(projectTableName, { andSearchText, orSearchText, notSearchText, city, country, state, albums, dateMin, dateMax, dateNullAnd, dateNullOr,
|
|
1514
|
+
async searchProjectPhotosParametrized(projectTableName, { andSearchText, orSearchText, notSearchText, city, country, state, albums, dateMin, dateMax, dateNullAnd, dateNullOr, ascOrDesc, bestOfSimilarSetsOnly, splitByTier, lastId, limit } = {}) {
|
|
1489
1515
|
this._ctx.requireTokens();
|
|
1490
1516
|
let path = `/api/v1/search/parametrized/${encodeURIComponent(projectTableName)}/`;
|
|
1491
1517
|
const query = new URLSearchParams();
|
|
@@ -1500,10 +1526,25 @@ class Search {
|
|
|
1500
1526
|
if (dateMax !== undefined) (Array.isArray(dateMax) ? dateMax : [dateMax]).forEach(v => query.append('date_max', v));
|
|
1501
1527
|
if (dateNullAnd !== undefined) (Array.isArray(dateNullAnd) ? dateNullAnd : [dateNullAnd]).forEach(v => query.append('date_null_and', v));
|
|
1502
1528
|
if (dateNullOr !== undefined) (Array.isArray(dateNullOr) ? dateNullOr : [dateNullOr]).forEach(v => query.append('date_null_or', v));
|
|
1503
|
-
if (
|
|
1529
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1504
1530
|
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1505
1531
|
if (splitByTier !== undefined) (Array.isArray(splitByTier) ? splitByTier : [splitByTier]).forEach(v => query.append('split_by_tier', v));
|
|
1506
|
-
if (
|
|
1532
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1533
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1534
|
+
const qs = query.toString();
|
|
1535
|
+
if (qs) path += '?' + qs;
|
|
1536
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1537
|
+
return data;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
async recallProjectPhotoIds(projectTableName, { ascOrDesc, bestOfSimilarSetsOnly, lastId, limit } = {}) {
|
|
1541
|
+
this._ctx.requireTokens();
|
|
1542
|
+
let path = `/api/v1/search/recall/${encodeURIComponent(projectTableName)}/`;
|
|
1543
|
+
const query = new URLSearchParams();
|
|
1544
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1545
|
+
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1546
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1547
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1507
1548
|
const qs = query.toString();
|
|
1508
1549
|
if (qs) path += '?' + qs;
|
|
1509
1550
|
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
package/dist/sdk.umd.js
CHANGED
|
@@ -177,6 +177,9 @@
|
|
|
177
177
|
const { postForm, postJson } = requireHttp();
|
|
178
178
|
const { OAuthError } = requireErrors();
|
|
179
179
|
|
|
180
|
+
// In-flight dedup key for client_credentials re-mints (no refresh_token to key on).
|
|
181
|
+
const CLIENT_CREDENTIALS_KEY = Symbol('client_credentials');
|
|
182
|
+
|
|
180
183
|
class OAuthClient {
|
|
181
184
|
/**
|
|
182
185
|
* @param {import('./types').OAuthClientConfig} config
|
|
@@ -315,15 +318,27 @@
|
|
|
315
318
|
return { data: json, updatedTokens: null };
|
|
316
319
|
}
|
|
317
320
|
|
|
318
|
-
// 401:
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
|
|
321
|
+
// 401: re-authenticate, then retry once.
|
|
322
|
+
// - User sessions (refresh_token present) use the refresh_token grant. The server
|
|
323
|
+
// rotates the token one-time, so concurrent callers share one in-flight call
|
|
324
|
+
// (a second rotation would get invalid_grant).
|
|
325
|
+
// - Machine-to-machine sessions (no refresh_token, client_secret configured) re-mint
|
|
326
|
+
// via client_credentials, which issues no refresh token to rotate (RFC 6749 §4.4).
|
|
327
|
+
// - With neither a refresh_token nor a client_secret there is nothing to retry with.
|
|
328
|
+
if (!refreshToken && !this._config.clientSecret) {
|
|
329
|
+
throw OAuthError.fromResponse(401, await firstResponse.json());
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const reauthKey = refreshToken || CLIENT_CREDENTIALS_KEY;
|
|
333
|
+
let pending = this._inFlightRefreshes.get(reauthKey);
|
|
322
334
|
if (!pending) {
|
|
323
|
-
|
|
324
|
-
this.
|
|
335
|
+
const reauth = refreshToken
|
|
336
|
+
? this.refreshAccessToken(refreshToken)
|
|
337
|
+
: this.getClientCredentialsToken();
|
|
338
|
+
pending = reauth.finally(() => {
|
|
339
|
+
this._inFlightRefreshes.delete(reauthKey);
|
|
325
340
|
});
|
|
326
|
-
this._inFlightRefreshes.set(
|
|
341
|
+
this._inFlightRefreshes.set(reauthKey, pending);
|
|
327
342
|
}
|
|
328
343
|
const newTokens = await pending;
|
|
329
344
|
|
|
@@ -1129,6 +1144,17 @@
|
|
|
1129
1144
|
return data;
|
|
1130
1145
|
}
|
|
1131
1146
|
|
|
1147
|
+
async getPhotoIdsByPersons(projectTableName, { personId } = {}) {
|
|
1148
|
+
this._ctx.requireTokens();
|
|
1149
|
+
let path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photos`;
|
|
1150
|
+
const query = new URLSearchParams();
|
|
1151
|
+
if (personId !== undefined) (Array.isArray(personId) ? personId : [personId]).forEach(v => query.append('person_id', v));
|
|
1152
|
+
const qs = query.toString();
|
|
1153
|
+
if (qs) path += '?' + qs;
|
|
1154
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1155
|
+
return data;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1132
1158
|
async getAllPersonsFromPhoto(projectTableName, photoId) {
|
|
1133
1159
|
this._ctx.requireTokens();
|
|
1134
1160
|
const path = `/api/v1/person/${encodeURIComponent(projectTableName)}/photo/${encodeURIComponent(photoId)}`;
|
|
@@ -1491,7 +1517,7 @@
|
|
|
1491
1517
|
return data;
|
|
1492
1518
|
}
|
|
1493
1519
|
|
|
1494
|
-
async searchProjectPhotosParametrized(projectTableName, { andSearchText, orSearchText, notSearchText, city, country, state, albums, dateMin, dateMax, dateNullAnd, dateNullOr,
|
|
1520
|
+
async searchProjectPhotosParametrized(projectTableName, { andSearchText, orSearchText, notSearchText, city, country, state, albums, dateMin, dateMax, dateNullAnd, dateNullOr, ascOrDesc, bestOfSimilarSetsOnly, splitByTier, lastId, limit } = {}) {
|
|
1495
1521
|
this._ctx.requireTokens();
|
|
1496
1522
|
let path = `/api/v1/search/parametrized/${encodeURIComponent(projectTableName)}/`;
|
|
1497
1523
|
const query = new URLSearchParams();
|
|
@@ -1506,10 +1532,25 @@
|
|
|
1506
1532
|
if (dateMax !== undefined) (Array.isArray(dateMax) ? dateMax : [dateMax]).forEach(v => query.append('date_max', v));
|
|
1507
1533
|
if (dateNullAnd !== undefined) (Array.isArray(dateNullAnd) ? dateNullAnd : [dateNullAnd]).forEach(v => query.append('date_null_and', v));
|
|
1508
1534
|
if (dateNullOr !== undefined) (Array.isArray(dateNullOr) ? dateNullOr : [dateNullOr]).forEach(v => query.append('date_null_or', v));
|
|
1509
|
-
if (
|
|
1535
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1510
1536
|
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1511
1537
|
if (splitByTier !== undefined) (Array.isArray(splitByTier) ? splitByTier : [splitByTier]).forEach(v => query.append('split_by_tier', v));
|
|
1512
|
-
if (
|
|
1538
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1539
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1540
|
+
const qs = query.toString();
|
|
1541
|
+
if (qs) path += '?' + qs;
|
|
1542
|
+
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|
|
1543
|
+
return data;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
async recallProjectPhotoIds(projectTableName, { ascOrDesc, bestOfSimilarSetsOnly, lastId, limit } = {}) {
|
|
1547
|
+
this._ctx.requireTokens();
|
|
1548
|
+
let path = `/api/v1/search/recall/${encodeURIComponent(projectTableName)}/`;
|
|
1549
|
+
const query = new URLSearchParams();
|
|
1550
|
+
if (ascOrDesc !== undefined) (Array.isArray(ascOrDesc) ? ascOrDesc : [ascOrDesc]).forEach(v => query.append('asc_or_desc', v));
|
|
1551
|
+
if (bestOfSimilarSetsOnly !== undefined) (Array.isArray(bestOfSimilarSetsOnly) ? bestOfSimilarSetsOnly : [bestOfSimilarSetsOnly]).forEach(v => query.append('best_of_similar_sets_only', v));
|
|
1552
|
+
if (lastId !== undefined) (Array.isArray(lastId) ? lastId : [lastId]).forEach(v => query.append('last_id', v));
|
|
1553
|
+
if (limit !== undefined) (Array.isArray(limit) ? limit : [limit]).forEach(v => query.append('limit', v));
|
|
1513
1554
|
const qs = query.toString();
|
|
1514
1555
|
if (qs) path += '?' + qs;
|
|
1515
1556
|
const { data } = await this._ctx.client.request(path, 'GET', this._ctx.accessToken, this._ctx.refreshToken);
|