@overmap-ai/core 1.0.60-sdk-refactor.3 → 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.
@@ -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" | "url" | "none" | "numeric" | "tel" | "decimal" | undefined;
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;
@@ -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";
@@ -13710,7 +13710,7 @@ const selectOrganization = (id) => (state) => {
13710
13710
  return state.organizationReducer.organizations[id];
13711
13711
  };
13712
13712
  const organizationReducer = organizationSlice.reducer;
13713
- const createOfflineAction = (request2, baseUrl) => {
13713
+ const createOfflineAction = (request2, baseUrl, serviceName) => {
13714
13714
  const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
13715
13715
  return {
13716
13716
  payload: requestWithUuid,
@@ -13720,7 +13720,8 @@ const createOfflineAction = (request2, baseUrl) => {
13720
13720
  effect: {
13721
13721
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
13722
13722
  request: requestWithUuid,
13723
- BASE_URL: baseUrl
13723
+ BASE_URL: baseUrl,
13724
+ serviceName
13724
13725
  }
13725
13726
  }
13726
13727
  }
@@ -13744,8 +13745,8 @@ const outboxSlice = createSlice({
13744
13745
  },
13745
13746
  prepare: (payload) => {
13746
13747
  console.debug("Preparing to enqueue request", payload);
13747
- const { BASE_URL, ...rest } = payload;
13748
- return createOfflineAction(rest, BASE_URL);
13748
+ const { BASE_URL, serviceName, ...rest } = payload;
13749
+ return createOfflineAction(rest, BASE_URL, serviceName);
13749
13750
  }
13750
13751
  },
13751
13752
  markForDeletion(state, action) {
@@ -15066,24 +15067,16 @@ function extractResponseFromError(error2) {
15066
15067
  return void 0;
15067
15068
  }
15068
15069
  async function performRequest(action, client) {
15069
- async function checkToken() {
15070
- if (client.auth.tokenIsExpiringSoon()) {
15071
- await client.auth.renewTokens();
15072
- }
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`);
15073
15073
  }
15074
15074
  const state = client.store.getState();
15075
15075
  if (state.outboxReducer.deletedRequests.includes(action.payload.uuid)) {
15076
15076
  throw new Error("Request was marked for deletion");
15077
15077
  }
15078
15078
  if (action.payload.checkAuth !== false) {
15079
- try {
15080
- await checkToken();
15081
- } catch (e) {
15082
- if (e instanceof APIError) {
15083
- await client.auth.logout();
15084
- return Promise.reject(e);
15085
- }
15086
- }
15079
+ await serviceOfRequest.auth.prepareAuth();
15087
15080
  }
15088
15081
  const defaultSettings = {
15089
15082
  queryParams: "",
@@ -15097,7 +15090,6 @@ async function performRequest(action, client) {
15097
15090
  const requestDetails = offlineEffect.request;
15098
15091
  let url = requestDetails.url;
15099
15092
  const file = attachmentHash ? await client.files.fetchCache(attachmentHash) : void 0;
15100
- const accessToken = selectAccessToken(state);
15101
15093
  if (attachmentHash && !file) {
15102
15094
  throw new Error(`Cannot upload file ${attachmentHash} because it's not cached.`);
15103
15095
  }
@@ -15150,7 +15142,8 @@ async function performRequest(action, client) {
15150
15142
  const selectedRequest = methodRequestMapping[method];
15151
15143
  let requestToSend = selectedRequest();
15152
15144
  if (isAuthNeeded) {
15153
- requestToSend = requestToSend.set("Authorization", `Bearer ${accessToken}`);
15145
+ const authHeader = serviceOfRequest.auth.getAuthHeader();
15146
+ requestToSend = requestToSend.set("Authorization", authHeader);
15154
15147
  }
15155
15148
  if (headers) {
15156
15149
  requestToSend = requestToSend.set(headers);
@@ -15161,32 +15154,8 @@ async function performRequest(action, client) {
15161
15154
  const errorResponse = extractResponseFromError(error2);
15162
15155
  const status = errorResponse == null ? void 0 : errorResponse.status;
15163
15156
  if (status === 401) {
15164
- if (url.endsWith("/token/refresh/")) {
15165
- if (state.authReducer.isLoggedIn) {
15166
- console.warn("No signed-in user to sign out.");
15167
- }
15168
- await client.auth.logout();
15169
- throw new APIError({
15170
- message: "You have been signed out due to inactivity.",
15171
- response: errorResponse,
15172
- discard: true,
15173
- innerError: error2
15174
- });
15175
- }
15176
- if (state.authReducer.isLoggedIn) {
15177
- console.debug("Forbidden; renewing tokens and retrying.");
15178
- await client.auth.renewTokens();
15179
- console.debug("Successfully renewed tokens; retrying request.");
15180
- return requestToSend.query(queryParams);
15181
- } else {
15182
- console.debug("Forbidden; user is not logged in.");
15183
- throw new APIError({
15184
- message: "Incorrect username or password.",
15185
- response: errorResponse,
15186
- discard: true,
15187
- innerError: error2
15188
- });
15189
- }
15157
+ await serviceOfRequest.auth.handleUnauthorized(requestToSend, errorResponse);
15158
+ return requestToSend.query(queryParams);
15190
15159
  }
15191
15160
  throw new APIError({ response: errorResponse, innerError: error2, discard: discardStatuses.includes(status) });
15192
15161
  }
@@ -15359,27 +15328,17 @@ class BaseSDK {
15359
15328
  __publicField(this, "store");
15360
15329
  this.store = store;
15361
15330
  }
15362
- /**
15363
- * Enqueues an API request to the offline outbox.
15364
- * @param requestDetails An SDKRequest object containing the details of the request.
15365
- * @param host The base URL of the API to send the request to.
15366
- * @protected
15367
- */
15368
- async enqueueRequest(requestDetails, host) {
15369
- return this._enqueueRequest(requestDetails, host).then((result) => {
15331
+ async enqueueRequest(requestDetails, host, serviceName) {
15332
+ return this._enqueueRequest(requestDetails, host, serviceName).then((result) => {
15370
15333
  if (result instanceof APIError) {
15371
15334
  throw result;
15372
15335
  }
15373
15336
  return result;
15374
15337
  });
15375
15338
  }
15376
- /**
15377
- * Enqueues an API request to the Redux Offline outbox
15378
- * @protected
15379
- */
15380
- _enqueueRequest(requestDetails, host) {
15339
+ _enqueueRequest(requestDetails, host, serviceName) {
15381
15340
  const promise = new DeferredPromise();
15382
- const requestDetailsWithBaseUrl = { ...requestDetails, BASE_URL: host };
15341
+ const requestDetailsWithBaseUrl = { ...requestDetails, BASE_URL: host, serviceName };
15383
15342
  if (requestDetails.immediate) {
15384
15343
  const requestWithUuid = {
15385
15344
  ...requestDetailsWithBaseUrl,
@@ -15393,7 +15352,8 @@ class BaseSDK {
15393
15352
  effect: {
15394
15353
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
15395
15354
  request: requestWithUuid,
15396
- BASE_URL: host
15355
+ BASE_URL: host,
15356
+ serviceName
15397
15357
  }
15398
15358
  }
15399
15359
  }
@@ -15449,18 +15409,13 @@ const initSDK = (store, sdk) => {
15449
15409
  setClientStore(store);
15450
15410
  return sdkInstance;
15451
15411
  };
15452
- class BaseApiService {
15412
+ class BaseAuthService {
15453
15413
  constructor(sdk) {
15454
15414
  __publicField(this, "client");
15455
15415
  this.client = sdk;
15456
15416
  }
15457
- /**
15458
- * Enqueues an API request to the offline outbox.
15459
- * @param requestDetails An SDKRequest object containing the details of the request.
15460
- * @protected
15461
- */
15462
15417
  async enqueueRequest(requestDetails) {
15463
- return this.client.enqueueRequest(requestDetails, this.host);
15418
+ return this.client.enqueueRequest(requestDetails, this.host, this.constructor.name);
15464
15419
  }
15465
15420
  dispatch(action) {
15466
15421
  this.client.store.dispatch(action);
@@ -15474,42 +15429,15 @@ function parseTokens(response) {
15474
15429
  throw new Error("Missing refresh token");
15475
15430
  return { accessToken: response.access, refreshToken: response.refresh };
15476
15431
  }
15477
- class AuthService extends BaseApiService {
15432
+ class JWTService extends BaseAuthService {
15478
15433
  constructor() {
15479
15434
  super(...arguments);
15435
+ // AUTH below
15480
15436
  __publicField(this, "_getAccessToken", () => this.client.store.getState().authReducer.accessToken);
15481
15437
  __publicField(this, "_getRefreshToken", () => this.client.store.getState().authReducer.refreshToken);
15482
15438
  // _getTokenPair and _getRenewedTokens don't need to use enqueueRequest from the BaseApiService because
15483
15439
  // they are very simple. However, if we need robust error handling or want these operations to queue in the Outbox,
15484
15440
  // we will use enqueueRequest.
15485
- /**
15486
- * Takes credentials and gets a token pair
15487
- * @async
15488
- * @param credentials The username and password for obtaining a token pair
15489
- * @param logoutOnFailure Whether to log out if the request fails
15490
- * @returns An array containing two elements: 1) a Promise for the access and refresh tokens, and 2) the UUID of the
15491
- * request, so the request can be cancelled if necessary.
15492
- */
15493
- __publicField(this, "_getTokenPair", (credentials, logoutOnFailure = true) => {
15494
- const uuid = v4();
15495
- const responsePromise = this.enqueueRequest({
15496
- uuid,
15497
- description: "Get token pair",
15498
- method: HttpMethod.POST,
15499
- url: "/api/token/",
15500
- payload: credentials,
15501
- isAuthNeeded: false,
15502
- checkAuth: false,
15503
- blockers: [],
15504
- blocks: []
15505
- }).then(parseTokens).catch((e) => {
15506
- if (logoutOnFailure) {
15507
- void this.logout().then();
15508
- }
15509
- throw e;
15510
- });
15511
- return [responsePromise, uuid];
15512
- });
15513
15441
  /**
15514
15442
  * Takes refresh token and gets a new token pair
15515
15443
  * @async
@@ -15549,34 +15477,6 @@ class AuthService extends BaseApiService {
15549
15477
  return { accessToken: response.access, refreshToken: response.refresh };
15550
15478
  });
15551
15479
  }
15552
- /**
15553
- * Attempts to log into Hemora using given credentials
15554
- * @param {string} username
15555
- * @param {string} password
15556
- */
15557
- async login(username, password) {
15558
- const [promise, uuid] = this._getTokenPair({ username, password }, false);
15559
- const initialDataUuid = v4();
15560
- const timeout = 5;
15561
- let timedOut = false;
15562
- const timeoutPromise = new Promise((_, reject) => {
15563
- setTimeout(() => {
15564
- timedOut = true;
15565
- this.dispatch(markForDeletion(uuid));
15566
- this.dispatch(markForDeletion(initialDataUuid));
15567
- reject(new APIError({ message: `Request timed out after ${timeout} seconds` }));
15568
- }, timeout * 1e3);
15569
- });
15570
- const successPromise = promise.then((tokens) => {
15571
- if (timedOut) {
15572
- return void 0;
15573
- }
15574
- this.dispatch(setTokens(tokens));
15575
- this.dispatch(setLoggedIn(true));
15576
- this.dispatch({ type: "rehydrated/setRehydrated", payload: true });
15577
- });
15578
- return Promise.race([timeoutPromise, successPromise]);
15579
- }
15580
15480
  /**
15581
15481
  * Logs the user out
15582
15482
  */
@@ -15612,6 +15512,103 @@ class AuthService extends BaseApiService {
15612
15512
  throw e;
15613
15513
  }
15614
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
+ }
15615
15612
  /**
15616
15613
  * Register a new user
15617
15614
  */
@@ -15639,25 +15636,6 @@ class AuthService extends BaseApiService {
15639
15636
  blocks: []
15640
15637
  });
15641
15638
  }
15642
- /**
15643
- * Checks whether the tokens will be expiring soon
15644
- * @returns {boolean}
15645
- */
15646
- tokenIsExpiringSoon() {
15647
- const accessToken = this._getAccessToken();
15648
- if (!accessToken) {
15649
- return false;
15650
- }
15651
- const currentDate = Date.now() / 1e3;
15652
- let expiryDate;
15653
- try {
15654
- expiryDate = jwtDecode(accessToken).exp ?? currentDate;
15655
- } catch {
15656
- expiryDate = currentDate;
15657
- }
15658
- const secondsUntilExpiry = expiryDate - currentDate;
15659
- return secondsUntilExpiry < EXPIRING_SOON_THRESHOLD;
15660
- }
15661
15639
  async replaceProfilePicture(file) {
15662
15640
  const hash = await hashFile(file);
15663
15641
  await this.client.files.addCache(file, hash);
@@ -15707,6 +15685,22 @@ class AuthService extends BaseApiService {
15707
15685
  });
15708
15686
  }
15709
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
+ }
15710
15704
  class CategoryService extends BaseApiService {
15711
15705
  add(category, workspaceId) {
15712
15706
  const offlineCategory = offline(category);
@@ -18105,18 +18099,17 @@ class FileService extends BaseApiService {
18105
18099
  }
18106
18100
  class EmailVerificationService extends BaseApiService {
18107
18101
  async getVerificationCode(verificationCode) {
18108
- const requestDetails = {
18102
+ return this.enqueueRequest({
18109
18103
  description: "Get verification code",
18110
18104
  method: HttpMethod.GET,
18111
18105
  url: `/verification/email-verification/${verificationCode}/`,
18112
18106
  isAuthNeeded: false,
18113
18107
  blockers: [],
18114
18108
  blocks: []
18115
- };
18116
- return this.enqueueRequest(requestDetails);
18109
+ });
18117
18110
  }
18118
18111
  validateVerificationCode(verificationCode, payload = void 0) {
18119
- const requestDetails = {
18112
+ return this.enqueueRequest({
18120
18113
  description: "Validate verification code",
18121
18114
  method: HttpMethod.POST,
18122
18115
  url: `/verification/email-verification/${verificationCode}/`,
@@ -18124,8 +18117,7 @@ class EmailVerificationService extends BaseApiService {
18124
18117
  payload,
18125
18118
  blockers: [],
18126
18119
  blocks: []
18127
- };
18128
- return this.enqueueRequest(requestDetails);
18120
+ });
18129
18121
  }
18130
18122
  }
18131
18123
  class EmailDomainsService extends BaseApiService {
@@ -18770,13 +18762,13 @@ export {
18770
18762
  AssetTypeAttachmentService,
18771
18763
  AssetTypeService,
18772
18764
  AttachmentModel,
18773
- AuthService,
18774
18765
  BaseApiService,
18775
18766
  BaseField,
18776
18767
  BaseFormElement,
18777
18768
  BaseSDK,
18778
18769
  BooleanField,
18779
18770
  BooleanInput,
18771
+ CLASS_NAME_TO_SERVICE,
18780
18772
  CategoryService,
18781
18773
  ColorPicker,
18782
18774
  Colors,
@@ -18814,6 +18806,7 @@ export {
18814
18806
  IssueTypeService,
18815
18807
  IssueUpdateChange,
18816
18808
  IssueUpdateService,
18809
+ JWTService,
18817
18810
  LicenseLevel,
18818
18811
  LicenseService,
18819
18812
  LicenseStatus,
@@ -19410,6 +19403,8 @@ export {
19410
19403
  userSlice,
19411
19404
  validateForm,
19412
19405
  valueIsFile,
19406
+ versioningReducer,
19407
+ versioningSlice,
19413
19408
  warningColor,
19414
19409
  workspaceReducer,
19415
19410
  workspaceSlice,