@overmap-ai/core 1.0.60-sdk-refactor.2 → 1.0.60-sdk-refactor.4
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/forms/fields/BaseField/hooks.d.ts +3 -3
- package/dist/overmap-core.js +235 -243
- package/dist/overmap-core.js.map +1 -1
- package/dist/overmap-core.umd.cjs +236 -244
- package/dist/overmap-core.umd.cjs.map +1 -1
- package/dist/sdk/base.d.ts +5 -16
- package/dist/sdk/sdk.d.ts +2 -1
- package/dist/sdk/services/BaseApiService.d.ts +4 -6
- package/dist/sdk/services/BaseAuthService.d.ts +16 -0
- package/dist/sdk/services/EmailVerificationService.d.ts +2 -1
- package/dist/sdk/services/FileService.d.ts +1 -1
- package/dist/sdk/services/{AuthService.d.ts → JWTAuthService.d.ts} +17 -23
- package/dist/sdk/services/index.d.ts +1 -1
- package/dist/sdk/typings.d.ts +1 -0
- package/dist/store/slices/index.d.ts +1 -0
- package/dist/store/slices/outboxSlice.d.ts +3 -1
- package/dist/store/store.d.ts +2 -3
- package/package.json +1 -1
|
@@ -64,7 +64,7 @@ export declare const useFormikInput: <TField extends AnyField>(props: ComponentP
|
|
|
64
64
|
readonly results?: number | undefined;
|
|
65
65
|
readonly security?: string | undefined;
|
|
66
66
|
readonly unselectable?: "on" | "off" | undefined;
|
|
67
|
-
readonly inputMode?: "search" | "text" | "email" | "
|
|
67
|
+
readonly inputMode?: "search" | "text" | "email" | "none" | "url" | "numeric" | "tel" | "decimal" | undefined;
|
|
68
68
|
readonly is?: string | undefined;
|
|
69
69
|
readonly "aria-activedescendant"?: string | undefined;
|
|
70
70
|
readonly "aria-atomic"?: (boolean | "true" | "false") | undefined;
|
|
@@ -280,10 +280,10 @@ export declare const useFormikInput: <TField extends AnyField>(props: ComponentP
|
|
|
280
280
|
readonly onAnimationIterationCapture?: import("react").AnimationEventHandler<HTMLElement> | undefined;
|
|
281
281
|
readonly onTransitionEnd?: import("react").TransitionEventHandler<HTMLElement> | undefined;
|
|
282
282
|
readonly onTransitionEndCapture?: import("react").TransitionEventHandler<HTMLElement> | undefined;
|
|
283
|
-
readonly headers?: string | undefined;
|
|
284
|
-
readonly method?: string | undefined;
|
|
285
283
|
readonly href?: string | undefined;
|
|
286
284
|
readonly download?: any;
|
|
285
|
+
readonly headers?: string | undefined;
|
|
286
|
+
readonly method?: string | undefined;
|
|
287
287
|
readonly placeholder?: string | undefined;
|
|
288
288
|
readonly required?: boolean | undefined;
|
|
289
289
|
readonly target?: string | undefined;
|
package/dist/overmap-core.js
CHANGED
|
@@ -35,8 +35,8 @@ import createMigration from "redux-persist-migrate";
|
|
|
35
35
|
import { createSlice, createSelector, combineReducers, createNextState } from "@reduxjs/toolkit";
|
|
36
36
|
import request from "superagent";
|
|
37
37
|
import { shallowEqual as shallowEqual$1 } from "react-redux";
|
|
38
|
-
import jwtDecode from "jwt-decode";
|
|
39
38
|
import { RESET_STATE } from "@redux-offline/redux-offline/lib/constants";
|
|
39
|
+
import jwtDecode from "jwt-decode";
|
|
40
40
|
import { openDB } from "idb";
|
|
41
41
|
var HttpMethod = /* @__PURE__ */ ((HttpMethod2) => {
|
|
42
42
|
HttpMethod2["GET"] = "GET";
|
|
@@ -12187,23 +12187,6 @@ class APIError extends Error {
|
|
|
12187
12187
|
this.options = options;
|
|
12188
12188
|
}
|
|
12189
12189
|
}
|
|
12190
|
-
class BaseApiService {
|
|
12191
|
-
constructor(sdk) {
|
|
12192
|
-
__publicField(this, "client");
|
|
12193
|
-
this.client = sdk;
|
|
12194
|
-
}
|
|
12195
|
-
/**
|
|
12196
|
-
* Enqueues an API request to the offline outbox.
|
|
12197
|
-
* @param requestDetails An SDKRequest object containing the details of the request.
|
|
12198
|
-
* @protected
|
|
12199
|
-
*/
|
|
12200
|
-
async enqueueRequest(requestDetails) {
|
|
12201
|
-
return this.client.enqueueRequest(requestDetails, this.host);
|
|
12202
|
-
}
|
|
12203
|
-
dispatch(action) {
|
|
12204
|
-
this.client.store.dispatch(action);
|
|
12205
|
-
}
|
|
12206
|
-
}
|
|
12207
12190
|
var randomString = function randomString2() {
|
|
12208
12191
|
return Math.random().toString(36).substring(7).split("").join(".");
|
|
12209
12192
|
};
|
|
@@ -13727,7 +13710,7 @@ const selectOrganization = (id) => (state) => {
|
|
|
13727
13710
|
return state.organizationReducer.organizations[id];
|
|
13728
13711
|
};
|
|
13729
13712
|
const organizationReducer = organizationSlice.reducer;
|
|
13730
|
-
const createOfflineAction = (request2, baseUrl) => {
|
|
13713
|
+
const createOfflineAction = (request2, baseUrl, serviceName) => {
|
|
13731
13714
|
const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
|
|
13732
13715
|
return {
|
|
13733
13716
|
payload: requestWithUuid,
|
|
@@ -13737,7 +13720,8 @@ const createOfflineAction = (request2, baseUrl) => {
|
|
|
13737
13720
|
effect: {
|
|
13738
13721
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13739
13722
|
request: requestWithUuid,
|
|
13740
|
-
BASE_URL: baseUrl
|
|
13723
|
+
BASE_URL: baseUrl,
|
|
13724
|
+
serviceName
|
|
13741
13725
|
}
|
|
13742
13726
|
}
|
|
13743
13727
|
}
|
|
@@ -13761,8 +13745,8 @@ const outboxSlice = createSlice({
|
|
|
13761
13745
|
},
|
|
13762
13746
|
prepare: (payload) => {
|
|
13763
13747
|
console.debug("Preparing to enqueue request", payload);
|
|
13764
|
-
const { BASE_URL, ...rest } = payload;
|
|
13765
|
-
return createOfflineAction(rest, BASE_URL);
|
|
13748
|
+
const { BASE_URL, serviceName, ...rest } = payload;
|
|
13749
|
+
return createOfflineAction(rest, BASE_URL, serviceName);
|
|
13766
13750
|
}
|
|
13767
13751
|
},
|
|
13768
13752
|
markForDeletion(state, action) {
|
|
@@ -15083,24 +15067,16 @@ function extractResponseFromError(error2) {
|
|
|
15083
15067
|
return void 0;
|
|
15084
15068
|
}
|
|
15085
15069
|
async function performRequest(action, client) {
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
|
|
15089
|
-
}
|
|
15070
|
+
const serviceOfRequest = CLASS_NAME_TO_SERVICE[action.meta.offline.effect.serviceName];
|
|
15071
|
+
if (!serviceOfRequest) {
|
|
15072
|
+
throw new Error(`Service ${action.meta.offline.effect.serviceName} not found`);
|
|
15090
15073
|
}
|
|
15091
15074
|
const state = client.store.getState();
|
|
15092
15075
|
if (state.outboxReducer.deletedRequests.includes(action.payload.uuid)) {
|
|
15093
15076
|
throw new Error("Request was marked for deletion");
|
|
15094
15077
|
}
|
|
15095
15078
|
if (action.payload.checkAuth !== false) {
|
|
15096
|
-
|
|
15097
|
-
await checkToken();
|
|
15098
|
-
} catch (e) {
|
|
15099
|
-
if (e instanceof APIError) {
|
|
15100
|
-
await client.auth.logout();
|
|
15101
|
-
return Promise.reject(e);
|
|
15102
|
-
}
|
|
15103
|
-
}
|
|
15079
|
+
await serviceOfRequest.auth.prepareAuth();
|
|
15104
15080
|
}
|
|
15105
15081
|
const defaultSettings = {
|
|
15106
15082
|
queryParams: "",
|
|
@@ -15114,7 +15090,6 @@ async function performRequest(action, client) {
|
|
|
15114
15090
|
const requestDetails = offlineEffect.request;
|
|
15115
15091
|
let url = requestDetails.url;
|
|
15116
15092
|
const file = attachmentHash ? await client.files.fetchCache(attachmentHash) : void 0;
|
|
15117
|
-
const accessToken = selectAccessToken(state);
|
|
15118
15093
|
if (attachmentHash && !file) {
|
|
15119
15094
|
throw new Error(`Cannot upload file ${attachmentHash} because it's not cached.`);
|
|
15120
15095
|
}
|
|
@@ -15167,7 +15142,8 @@ async function performRequest(action, client) {
|
|
|
15167
15142
|
const selectedRequest = methodRequestMapping[method];
|
|
15168
15143
|
let requestToSend = selectedRequest();
|
|
15169
15144
|
if (isAuthNeeded) {
|
|
15170
|
-
|
|
15145
|
+
const authHeader = serviceOfRequest.auth.getAuthHeader();
|
|
15146
|
+
requestToSend = requestToSend.set("Authorization", authHeader);
|
|
15171
15147
|
}
|
|
15172
15148
|
if (headers) {
|
|
15173
15149
|
requestToSend = requestToSend.set(headers);
|
|
@@ -15178,32 +15154,8 @@ async function performRequest(action, client) {
|
|
|
15178
15154
|
const errorResponse = extractResponseFromError(error2);
|
|
15179
15155
|
const status = errorResponse == null ? void 0 : errorResponse.status;
|
|
15180
15156
|
if (status === 401) {
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
console.warn("No signed-in user to sign out.");
|
|
15184
|
-
}
|
|
15185
|
-
await client.auth.logout();
|
|
15186
|
-
throw new APIError({
|
|
15187
|
-
message: "You have been signed out due to inactivity.",
|
|
15188
|
-
response: errorResponse,
|
|
15189
|
-
discard: true,
|
|
15190
|
-
innerError: error2
|
|
15191
|
-
});
|
|
15192
|
-
}
|
|
15193
|
-
if (state.authReducer.isLoggedIn) {
|
|
15194
|
-
console.debug("Forbidden; renewing tokens and retrying.");
|
|
15195
|
-
await client.auth.renewTokens();
|
|
15196
|
-
console.debug("Successfully renewed tokens; retrying request.");
|
|
15197
|
-
return requestToSend.query(queryParams);
|
|
15198
|
-
} else {
|
|
15199
|
-
console.debug("Forbidden; user is not logged in.");
|
|
15200
|
-
throw new APIError({
|
|
15201
|
-
message: "Incorrect username or password.",
|
|
15202
|
-
response: errorResponse,
|
|
15203
|
-
discard: true,
|
|
15204
|
-
innerError: error2
|
|
15205
|
-
});
|
|
15206
|
-
}
|
|
15157
|
+
await serviceOfRequest.auth.handleUnauthorized(requestToSend, errorResponse);
|
|
15158
|
+
return requestToSend.query(queryParams);
|
|
15207
15159
|
}
|
|
15208
15160
|
throw new APIError({ response: errorResponse, innerError: error2, discard: discardStatuses.includes(status) });
|
|
15209
15161
|
}
|
|
@@ -15371,6 +15323,104 @@ function retry(_action, _retries) {
|
|
|
15371
15323
|
getClientStore().dispatch(_setLatestRetryTime((/* @__PURE__ */ new Date()).getTime()));
|
|
15372
15324
|
return OUTBOX_RETRY_DELAY;
|
|
15373
15325
|
}
|
|
15326
|
+
class BaseSDK {
|
|
15327
|
+
constructor(store) {
|
|
15328
|
+
__publicField(this, "store");
|
|
15329
|
+
this.store = store;
|
|
15330
|
+
}
|
|
15331
|
+
async enqueueRequest(requestDetails, host, serviceName) {
|
|
15332
|
+
return this._enqueueRequest(requestDetails, host, serviceName).then((result) => {
|
|
15333
|
+
if (result instanceof APIError) {
|
|
15334
|
+
throw result;
|
|
15335
|
+
}
|
|
15336
|
+
return result;
|
|
15337
|
+
});
|
|
15338
|
+
}
|
|
15339
|
+
_enqueueRequest(requestDetails, host, serviceName) {
|
|
15340
|
+
const promise = new DeferredPromise();
|
|
15341
|
+
const requestDetailsWithBaseUrl = { ...requestDetails, BASE_URL: host, serviceName };
|
|
15342
|
+
if (requestDetails.immediate) {
|
|
15343
|
+
const requestWithUuid = {
|
|
15344
|
+
...requestDetailsWithBaseUrl,
|
|
15345
|
+
uuid: requestDetails.uuid ?? v4()
|
|
15346
|
+
};
|
|
15347
|
+
const fullOfflineAction = {
|
|
15348
|
+
payload: requestWithUuid,
|
|
15349
|
+
type: "",
|
|
15350
|
+
meta: {
|
|
15351
|
+
offline: {
|
|
15352
|
+
effect: {
|
|
15353
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15354
|
+
request: requestWithUuid,
|
|
15355
|
+
BASE_URL: host,
|
|
15356
|
+
serviceName
|
|
15357
|
+
}
|
|
15358
|
+
}
|
|
15359
|
+
}
|
|
15360
|
+
};
|
|
15361
|
+
performRequest(fullOfflineAction, this).then((result) => {
|
|
15362
|
+
promise.resolve(result.body);
|
|
15363
|
+
}).catch((error2) => {
|
|
15364
|
+
discard(error2, fullOfflineAction);
|
|
15365
|
+
promise.reject(error2);
|
|
15366
|
+
});
|
|
15367
|
+
} else {
|
|
15368
|
+
const innerPromise = this.store.dispatch(
|
|
15369
|
+
enqueueRequest(requestDetailsWithBaseUrl)
|
|
15370
|
+
);
|
|
15371
|
+
const successOrUndefinedHandler = (response) => {
|
|
15372
|
+
if (response) {
|
|
15373
|
+
promise.resolve(response.body);
|
|
15374
|
+
} else {
|
|
15375
|
+
const error2 = new APIError({
|
|
15376
|
+
message: "Could not get a response from the server.",
|
|
15377
|
+
response,
|
|
15378
|
+
discard: true
|
|
15379
|
+
});
|
|
15380
|
+
promise.reject(error2);
|
|
15381
|
+
}
|
|
15382
|
+
};
|
|
15383
|
+
const errorHandler = (error2) => {
|
|
15384
|
+
if (error2 instanceof APIError) {
|
|
15385
|
+
error2.options.discard = true;
|
|
15386
|
+
} else {
|
|
15387
|
+
console.error(
|
|
15388
|
+
"Received an unexpected error while processing a request:",
|
|
15389
|
+
error2,
|
|
15390
|
+
"\nConverting error to APIError and discarding."
|
|
15391
|
+
);
|
|
15392
|
+
error2 = new APIError({
|
|
15393
|
+
message: "An error occurred while processing the request.",
|
|
15394
|
+
innerError: error2,
|
|
15395
|
+
discard: true
|
|
15396
|
+
});
|
|
15397
|
+
}
|
|
15398
|
+
promise.reject(error2);
|
|
15399
|
+
};
|
|
15400
|
+
innerPromise.then(successOrUndefinedHandler, errorHandler);
|
|
15401
|
+
}
|
|
15402
|
+
return promise;
|
|
15403
|
+
}
|
|
15404
|
+
// NOTE: these are currently expected to be present in the base SDK, not sure if that is desired
|
|
15405
|
+
}
|
|
15406
|
+
const initSDK = (store, sdk) => {
|
|
15407
|
+
const sdkInstance = new sdk(store);
|
|
15408
|
+
setClientSDK(sdkInstance);
|
|
15409
|
+
setClientStore(store);
|
|
15410
|
+
return sdkInstance;
|
|
15411
|
+
};
|
|
15412
|
+
class BaseAuthService {
|
|
15413
|
+
constructor(sdk) {
|
|
15414
|
+
__publicField(this, "client");
|
|
15415
|
+
this.client = sdk;
|
|
15416
|
+
}
|
|
15417
|
+
async enqueueRequest(requestDetails) {
|
|
15418
|
+
return this.client.enqueueRequest(requestDetails, this.host, this.constructor.name);
|
|
15419
|
+
}
|
|
15420
|
+
dispatch(action) {
|
|
15421
|
+
this.client.store.dispatch(action);
|
|
15422
|
+
}
|
|
15423
|
+
}
|
|
15374
15424
|
const EXPIRING_SOON_THRESHOLD = 1800;
|
|
15375
15425
|
function parseTokens(response) {
|
|
15376
15426
|
if (!response.access)
|
|
@@ -15379,43 +15429,15 @@ function parseTokens(response) {
|
|
|
15379
15429
|
throw new Error("Missing refresh token");
|
|
15380
15430
|
return { accessToken: response.access, refreshToken: response.refresh };
|
|
15381
15431
|
}
|
|
15382
|
-
class
|
|
15432
|
+
class JWTService extends BaseAuthService {
|
|
15383
15433
|
constructor() {
|
|
15384
15434
|
super(...arguments);
|
|
15385
|
-
|
|
15435
|
+
// AUTH below
|
|
15386
15436
|
__publicField(this, "_getAccessToken", () => this.client.store.getState().authReducer.accessToken);
|
|
15387
15437
|
__publicField(this, "_getRefreshToken", () => this.client.store.getState().authReducer.refreshToken);
|
|
15388
15438
|
// _getTokenPair and _getRenewedTokens don't need to use enqueueRequest from the BaseApiService because
|
|
15389
15439
|
// they are very simple. However, if we need robust error handling or want these operations to queue in the Outbox,
|
|
15390
15440
|
// we will use enqueueRequest.
|
|
15391
|
-
/**
|
|
15392
|
-
* Takes credentials and gets a token pair
|
|
15393
|
-
* @async
|
|
15394
|
-
* @param credentials The username and password for obtaining a token pair
|
|
15395
|
-
* @param logoutOnFailure Whether to log out if the request fails
|
|
15396
|
-
* @returns An array containing two elements: 1) a Promise for the access and refresh tokens, and 2) the UUID of the
|
|
15397
|
-
* request, so the request can be cancelled if necessary.
|
|
15398
|
-
*/
|
|
15399
|
-
__publicField(this, "_getTokenPair", (credentials, logoutOnFailure = true) => {
|
|
15400
|
-
const uuid = v4();
|
|
15401
|
-
const responsePromise = this.enqueueRequest({
|
|
15402
|
-
uuid,
|
|
15403
|
-
description: "Get token pair",
|
|
15404
|
-
method: HttpMethod.POST,
|
|
15405
|
-
url: "/api/token/",
|
|
15406
|
-
payload: credentials,
|
|
15407
|
-
isAuthNeeded: false,
|
|
15408
|
-
checkAuth: false,
|
|
15409
|
-
blockers: [],
|
|
15410
|
-
blocks: []
|
|
15411
|
-
}).then(parseTokens).catch((e) => {
|
|
15412
|
-
if (logoutOnFailure) {
|
|
15413
|
-
void this.logout().then();
|
|
15414
|
-
}
|
|
15415
|
-
throw e;
|
|
15416
|
-
});
|
|
15417
|
-
return [responsePromise, uuid];
|
|
15418
|
-
});
|
|
15419
15441
|
/**
|
|
15420
15442
|
* Takes refresh token and gets a new token pair
|
|
15421
15443
|
* @async
|
|
@@ -15455,34 +15477,6 @@ class AuthService extends BaseApiService {
|
|
|
15455
15477
|
return { accessToken: response.access, refreshToken: response.refresh };
|
|
15456
15478
|
});
|
|
15457
15479
|
}
|
|
15458
|
-
/**
|
|
15459
|
-
* Attempts to log into Hemora using given credentials
|
|
15460
|
-
* @param {string} username
|
|
15461
|
-
* @param {string} password
|
|
15462
|
-
*/
|
|
15463
|
-
async login(username, password) {
|
|
15464
|
-
const [promise, uuid] = this._getTokenPair({ username, password }, false);
|
|
15465
|
-
const initialDataUuid = v4();
|
|
15466
|
-
const timeout = 5;
|
|
15467
|
-
let timedOut = false;
|
|
15468
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
15469
|
-
setTimeout(() => {
|
|
15470
|
-
timedOut = true;
|
|
15471
|
-
this.dispatch(markForDeletion(uuid));
|
|
15472
|
-
this.dispatch(markForDeletion(initialDataUuid));
|
|
15473
|
-
reject(new APIError({ message: `Request timed out after ${timeout} seconds` }));
|
|
15474
|
-
}, timeout * 1e3);
|
|
15475
|
-
});
|
|
15476
|
-
const successPromise = promise.then((tokens) => {
|
|
15477
|
-
if (timedOut) {
|
|
15478
|
-
return void 0;
|
|
15479
|
-
}
|
|
15480
|
-
this.dispatch(setTokens(tokens));
|
|
15481
|
-
this.dispatch(setLoggedIn(true));
|
|
15482
|
-
this.dispatch({ type: "rehydrated/setRehydrated", payload: true });
|
|
15483
|
-
});
|
|
15484
|
-
return Promise.race([timeoutPromise, successPromise]);
|
|
15485
|
-
}
|
|
15486
15480
|
/**
|
|
15487
15481
|
* Logs the user out
|
|
15488
15482
|
*/
|
|
@@ -15518,6 +15512,103 @@ class AuthService extends BaseApiService {
|
|
|
15518
15512
|
throw e;
|
|
15519
15513
|
}
|
|
15520
15514
|
}
|
|
15515
|
+
/**
|
|
15516
|
+
* Checks whether the tokens will be expiring soon
|
|
15517
|
+
* @returns {boolean}
|
|
15518
|
+
*/
|
|
15519
|
+
tokenIsExpiringSoon() {
|
|
15520
|
+
const accessToken = this._getAccessToken();
|
|
15521
|
+
if (!accessToken) {
|
|
15522
|
+
return false;
|
|
15523
|
+
}
|
|
15524
|
+
const currentDate = Date.now() / 1e3;
|
|
15525
|
+
let expiryDate;
|
|
15526
|
+
try {
|
|
15527
|
+
expiryDate = jwtDecode(accessToken).exp ?? currentDate;
|
|
15528
|
+
} catch {
|
|
15529
|
+
expiryDate = currentDate;
|
|
15530
|
+
}
|
|
15531
|
+
const secondsUntilExpiry = expiryDate - currentDate;
|
|
15532
|
+
return secondsUntilExpiry < EXPIRING_SOON_THRESHOLD;
|
|
15533
|
+
}
|
|
15534
|
+
getAuthHeader() {
|
|
15535
|
+
const accesseToken = selectAccessToken(this.client.store.getState());
|
|
15536
|
+
return `Bearer ${accesseToken}`;
|
|
15537
|
+
}
|
|
15538
|
+
async prepareAuth() {
|
|
15539
|
+
if (!this.tokenIsExpiringSoon())
|
|
15540
|
+
return;
|
|
15541
|
+
try {
|
|
15542
|
+
await this.renewTokens();
|
|
15543
|
+
} catch (e) {
|
|
15544
|
+
if (e instanceof APIError) {
|
|
15545
|
+
await this.logout();
|
|
15546
|
+
}
|
|
15547
|
+
return Promise.reject(e);
|
|
15548
|
+
}
|
|
15549
|
+
}
|
|
15550
|
+
/* if not successfull in gracefully handling an unauthorized response, throw and APIError */
|
|
15551
|
+
async handleUnauthorized(request2, response) {
|
|
15552
|
+
const state = this.client.store.getState();
|
|
15553
|
+
if (request2.url.endsWith("/token/refresh/")) {
|
|
15554
|
+
if (state.authReducer.isLoggedIn) {
|
|
15555
|
+
console.warn("No signed-in user to sign out.");
|
|
15556
|
+
}
|
|
15557
|
+
await this.logout();
|
|
15558
|
+
throw new APIError({
|
|
15559
|
+
message: "You have been signed out due to inactivity.",
|
|
15560
|
+
response,
|
|
15561
|
+
discard: true
|
|
15562
|
+
});
|
|
15563
|
+
}
|
|
15564
|
+
if (state.authReducer.isLoggedIn) {
|
|
15565
|
+
await this.renewTokens();
|
|
15566
|
+
} else {
|
|
15567
|
+
console.debug("Forbidden; user is not logged in.");
|
|
15568
|
+
throw new APIError({
|
|
15569
|
+
message: "Incorrect username or password.",
|
|
15570
|
+
response,
|
|
15571
|
+
discard: true
|
|
15572
|
+
});
|
|
15573
|
+
}
|
|
15574
|
+
}
|
|
15575
|
+
/**
|
|
15576
|
+
* Attempts to log into Hemora using given credentials
|
|
15577
|
+
* @param {string} username
|
|
15578
|
+
* @param {string} password
|
|
15579
|
+
*/
|
|
15580
|
+
async initAuth(username, password) {
|
|
15581
|
+
const uuid = v4();
|
|
15582
|
+
const promise = this.enqueueRequest({
|
|
15583
|
+
uuid,
|
|
15584
|
+
description: "Get token pair",
|
|
15585
|
+
method: HttpMethod.POST,
|
|
15586
|
+
url: "/api/token/",
|
|
15587
|
+
payload: { username, password },
|
|
15588
|
+
isAuthNeeded: false,
|
|
15589
|
+
checkAuth: false,
|
|
15590
|
+
blockers: [],
|
|
15591
|
+
blocks: []
|
|
15592
|
+
}).then(parseTokens);
|
|
15593
|
+
const timeout = 5;
|
|
15594
|
+
let timedOut = false;
|
|
15595
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
15596
|
+
setTimeout(() => {
|
|
15597
|
+
timedOut = true;
|
|
15598
|
+
this.dispatch(markForDeletion(uuid));
|
|
15599
|
+
reject(new APIError({ message: `Request timed out after ${timeout} seconds` }));
|
|
15600
|
+
}, timeout * 1e3);
|
|
15601
|
+
});
|
|
15602
|
+
const successPromise = promise.then((tokens) => {
|
|
15603
|
+
if (timedOut) {
|
|
15604
|
+
return void 0;
|
|
15605
|
+
}
|
|
15606
|
+
this.dispatch(setTokens(tokens));
|
|
15607
|
+
this.dispatch(setLoggedIn(true));
|
|
15608
|
+
this.dispatch({ type: "rehydrated/setRehydrated", payload: true });
|
|
15609
|
+
});
|
|
15610
|
+
return Promise.race([timeoutPromise, successPromise]);
|
|
15611
|
+
}
|
|
15521
15612
|
/**
|
|
15522
15613
|
* Register a new user
|
|
15523
15614
|
*/
|
|
@@ -15545,25 +15636,6 @@ class AuthService extends BaseApiService {
|
|
|
15545
15636
|
blocks: []
|
|
15546
15637
|
});
|
|
15547
15638
|
}
|
|
15548
|
-
/**
|
|
15549
|
-
* Checks whether the tokens will be expiring soon
|
|
15550
|
-
* @returns {boolean}
|
|
15551
|
-
*/
|
|
15552
|
-
tokenIsExpiringSoon() {
|
|
15553
|
-
const accessToken = this._getAccessToken();
|
|
15554
|
-
if (!accessToken) {
|
|
15555
|
-
return false;
|
|
15556
|
-
}
|
|
15557
|
-
const currentDate = Date.now() / 1e3;
|
|
15558
|
-
let expiryDate;
|
|
15559
|
-
try {
|
|
15560
|
-
expiryDate = jwtDecode(accessToken).exp ?? currentDate;
|
|
15561
|
-
} catch {
|
|
15562
|
-
expiryDate = currentDate;
|
|
15563
|
-
}
|
|
15564
|
-
const secondsUntilExpiry = expiryDate - currentDate;
|
|
15565
|
-
return secondsUntilExpiry < EXPIRING_SOON_THRESHOLD;
|
|
15566
|
-
}
|
|
15567
15639
|
async replaceProfilePicture(file) {
|
|
15568
15640
|
const hash = await hashFile(file);
|
|
15569
15641
|
await this.client.files.addCache(file, hash);
|
|
@@ -15613,6 +15685,22 @@ class AuthService extends BaseApiService {
|
|
|
15613
15685
|
});
|
|
15614
15686
|
}
|
|
15615
15687
|
}
|
|
15688
|
+
const CLASS_NAME_TO_SERVICE = {};
|
|
15689
|
+
class BaseApiService {
|
|
15690
|
+
constructor(sdk, auth) {
|
|
15691
|
+
__publicField(this, "client");
|
|
15692
|
+
__publicField(this, "auth");
|
|
15693
|
+
CLASS_NAME_TO_SERVICE[this.constructor.name] = this;
|
|
15694
|
+
this.client = sdk;
|
|
15695
|
+
this.auth = auth;
|
|
15696
|
+
}
|
|
15697
|
+
async enqueueRequest(requestDetails) {
|
|
15698
|
+
return this.client.enqueueRequest(requestDetails, this.host, this.constructor.name);
|
|
15699
|
+
}
|
|
15700
|
+
dispatch(action) {
|
|
15701
|
+
this.client.store.dispatch(action);
|
|
15702
|
+
}
|
|
15703
|
+
}
|
|
15616
15704
|
class CategoryService extends BaseApiService {
|
|
15617
15705
|
add(category, workspaceId) {
|
|
15618
15706
|
const offlineCategory = offline(category);
|
|
@@ -18011,18 +18099,17 @@ class FileService extends BaseApiService {
|
|
|
18011
18099
|
}
|
|
18012
18100
|
class EmailVerificationService extends BaseApiService {
|
|
18013
18101
|
async getVerificationCode(verificationCode) {
|
|
18014
|
-
|
|
18102
|
+
return this.enqueueRequest({
|
|
18015
18103
|
description: "Get verification code",
|
|
18016
18104
|
method: HttpMethod.GET,
|
|
18017
18105
|
url: `/verification/email-verification/${verificationCode}/`,
|
|
18018
18106
|
isAuthNeeded: false,
|
|
18019
18107
|
blockers: [],
|
|
18020
18108
|
blocks: []
|
|
18021
|
-
};
|
|
18022
|
-
return this.enqueueRequest(requestDetails);
|
|
18109
|
+
});
|
|
18023
18110
|
}
|
|
18024
18111
|
validateVerificationCode(verificationCode, payload = void 0) {
|
|
18025
|
-
|
|
18112
|
+
return this.enqueueRequest({
|
|
18026
18113
|
description: "Validate verification code",
|
|
18027
18114
|
method: HttpMethod.POST,
|
|
18028
18115
|
url: `/verification/email-verification/${verificationCode}/`,
|
|
@@ -18030,8 +18117,7 @@ class EmailVerificationService extends BaseApiService {
|
|
|
18030
18117
|
payload,
|
|
18031
18118
|
blockers: [],
|
|
18032
18119
|
blocks: []
|
|
18033
|
-
};
|
|
18034
|
-
return this.enqueueRequest(requestDetails);
|
|
18120
|
+
});
|
|
18035
18121
|
}
|
|
18036
18122
|
}
|
|
18037
18123
|
class EmailDomainsService extends BaseApiService {
|
|
@@ -18665,103 +18751,6 @@ class TeamService extends BaseApiService {
|
|
|
18665
18751
|
this.dispatch(setTeams(result));
|
|
18666
18752
|
}
|
|
18667
18753
|
}
|
|
18668
|
-
class BaseSDK {
|
|
18669
|
-
constructor(store) {
|
|
18670
|
-
__publicField(this, "store");
|
|
18671
|
-
// NOTE: these are currently expected to be present in the base SDK, not sure if that is desired
|
|
18672
|
-
__publicField(this, "files", new FileService(this));
|
|
18673
|
-
__publicField(this, "auth", new AuthService(this));
|
|
18674
|
-
this.store = store;
|
|
18675
|
-
}
|
|
18676
|
-
/**
|
|
18677
|
-
* Enqueues an API request to the offline outbox.
|
|
18678
|
-
* @param requestDetails An SDKRequest object containing the details of the request.
|
|
18679
|
-
* @param host The base URL of the API to send the request to.
|
|
18680
|
-
* @protected
|
|
18681
|
-
*/
|
|
18682
|
-
async enqueueRequest(requestDetails, host) {
|
|
18683
|
-
return this._enqueueRequest(requestDetails, host).then((result) => {
|
|
18684
|
-
if (result instanceof APIError) {
|
|
18685
|
-
throw result;
|
|
18686
|
-
}
|
|
18687
|
-
return result;
|
|
18688
|
-
});
|
|
18689
|
-
}
|
|
18690
|
-
/**
|
|
18691
|
-
* Enqueues an API request to the Redux Offline outbox
|
|
18692
|
-
* @protected
|
|
18693
|
-
*/
|
|
18694
|
-
_enqueueRequest(requestDetails, host) {
|
|
18695
|
-
const promise = new DeferredPromise();
|
|
18696
|
-
const requestDetailsWithBaseUrl = { ...requestDetails, BASE_URL: host };
|
|
18697
|
-
if (requestDetails.immediate) {
|
|
18698
|
-
const requestWithUuid = {
|
|
18699
|
-
...requestDetailsWithBaseUrl,
|
|
18700
|
-
uuid: requestDetails.uuid ?? v4()
|
|
18701
|
-
};
|
|
18702
|
-
const fullOfflineAction = {
|
|
18703
|
-
payload: requestWithUuid,
|
|
18704
|
-
type: "",
|
|
18705
|
-
meta: {
|
|
18706
|
-
offline: {
|
|
18707
|
-
effect: {
|
|
18708
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18709
|
-
request: requestWithUuid,
|
|
18710
|
-
BASE_URL: host
|
|
18711
|
-
}
|
|
18712
|
-
}
|
|
18713
|
-
}
|
|
18714
|
-
};
|
|
18715
|
-
performRequest(fullOfflineAction, this).then((result) => {
|
|
18716
|
-
promise.resolve(result.body);
|
|
18717
|
-
}).catch((error2) => {
|
|
18718
|
-
discard(error2, fullOfflineAction);
|
|
18719
|
-
promise.reject(error2);
|
|
18720
|
-
});
|
|
18721
|
-
} else {
|
|
18722
|
-
const innerPromise = this.store.dispatch(
|
|
18723
|
-
enqueueRequest(requestDetailsWithBaseUrl)
|
|
18724
|
-
);
|
|
18725
|
-
const successOrUndefinedHandler = (response) => {
|
|
18726
|
-
if (response) {
|
|
18727
|
-
promise.resolve(response.body);
|
|
18728
|
-
} else {
|
|
18729
|
-
const error2 = new APIError({
|
|
18730
|
-
message: "Could not get a response from the server.",
|
|
18731
|
-
response,
|
|
18732
|
-
discard: true
|
|
18733
|
-
});
|
|
18734
|
-
promise.reject(error2);
|
|
18735
|
-
}
|
|
18736
|
-
};
|
|
18737
|
-
const errorHandler = (error2) => {
|
|
18738
|
-
if (error2 instanceof APIError) {
|
|
18739
|
-
error2.options.discard = true;
|
|
18740
|
-
} else {
|
|
18741
|
-
console.error(
|
|
18742
|
-
"Received an unexpected error while processing a request:",
|
|
18743
|
-
error2,
|
|
18744
|
-
"\nConverting error to APIError and discarding."
|
|
18745
|
-
);
|
|
18746
|
-
error2 = new APIError({
|
|
18747
|
-
message: "An error occurred while processing the request.",
|
|
18748
|
-
innerError: error2,
|
|
18749
|
-
discard: true
|
|
18750
|
-
});
|
|
18751
|
-
}
|
|
18752
|
-
promise.reject(error2);
|
|
18753
|
-
};
|
|
18754
|
-
innerPromise.then(successOrUndefinedHandler, errorHandler);
|
|
18755
|
-
}
|
|
18756
|
-
return promise;
|
|
18757
|
-
}
|
|
18758
|
-
}
|
|
18759
|
-
const initSDK = (store, sdk) => {
|
|
18760
|
-
const sdkInstance = new sdk(store);
|
|
18761
|
-
setClientSDK(sdkInstance);
|
|
18762
|
-
setClientStore(store);
|
|
18763
|
-
return sdkInstance;
|
|
18764
|
-
};
|
|
18765
18754
|
export {
|
|
18766
18755
|
APIError,
|
|
18767
18756
|
AgentService,
|
|
@@ -18773,13 +18762,13 @@ export {
|
|
|
18773
18762
|
AssetTypeAttachmentService,
|
|
18774
18763
|
AssetTypeService,
|
|
18775
18764
|
AttachmentModel,
|
|
18776
|
-
AuthService,
|
|
18777
18765
|
BaseApiService,
|
|
18778
18766
|
BaseField,
|
|
18779
18767
|
BaseFormElement,
|
|
18780
18768
|
BaseSDK,
|
|
18781
18769
|
BooleanField,
|
|
18782
18770
|
BooleanInput,
|
|
18771
|
+
CLASS_NAME_TO_SERVICE,
|
|
18783
18772
|
CategoryService,
|
|
18784
18773
|
ColorPicker,
|
|
18785
18774
|
Colors,
|
|
@@ -18817,6 +18806,7 @@ export {
|
|
|
18817
18806
|
IssueTypeService,
|
|
18818
18807
|
IssueUpdateChange,
|
|
18819
18808
|
IssueUpdateService,
|
|
18809
|
+
JWTService,
|
|
18820
18810
|
LicenseLevel,
|
|
18821
18811
|
LicenseService,
|
|
18822
18812
|
LicenseStatus,
|
|
@@ -19413,6 +19403,8 @@ export {
|
|
|
19413
19403
|
userSlice,
|
|
19414
19404
|
validateForm,
|
|
19415
19405
|
valueIsFile,
|
|
19406
|
+
versioningReducer,
|
|
19407
|
+
versioningSlice,
|
|
19416
19408
|
warningColor,
|
|
19417
19409
|
workspaceReducer,
|
|
19418
19410
|
workspaceSlice,
|