@mindline/sync 1.0.46 → 1.0.49

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.
@@ -2,6 +2,6 @@
2
2
  "ExpandedNodes": [
3
3
  ""
4
4
  ],
5
- "SelectedNode": "\\index.ts",
5
+ "SelectedNode": "\\package.json",
6
6
  "PreviewInSolutionExplorer": false
7
7
  }
package/.vs/slnx.sqlite CHANGED
Binary file
Binary file
package/hybridspa.ts CHANGED
@@ -893,7 +893,14 @@ export async function readerPost(
893
893
  if (response.status === 200 && response.statusText === "OK") {
894
894
  console.log(`Successful POST to /startSync: ${readerEndpoint}`);
895
895
  let jsonResponse = await response.json();
896
- result.array = JSON.parse(jsonResponse.PayloadStr);
896
+ if (jsonResponse.PayloadStr != "") {
897
+ result.array = JSON.parse(jsonResponse.PayloadStr);
898
+ }
899
+ else {
900
+ result.result = false;
901
+ result.error = "readerPost: blank payload returned, sync may be disabled on back end";
902
+ result.status = 500;
903
+ }
897
904
  return result;
898
905
  } else {
899
906
  result.error = await processErrors(response);
package/index.d.ts CHANGED
@@ -116,7 +116,6 @@ declare module "@mindline/sync" {
116
116
  export type TaskType = "initialization" |
117
117
  "authenticate user" |
118
118
  "reload React" |
119
- "PUT tenant" |
120
119
  "GET tenant details" |
121
120
  "POST config init" |
122
121
  "GET workspaces" |
@@ -233,6 +232,7 @@ declare module "@mindline/sync" {
233
232
  export function groupsGet(instance: IPublicClientApplication, user: User | undefined, groupSearchString: string): Promise<{groups: Group[], error: string}>;
234
233
  export function signIn(user: User, tasks: TaskArray): void;
235
234
  export function signInIncrementally(user: User, scope: string): void;
235
+ export function requestAdminConsent(user: User, scope: string): void;
236
236
  export function signOut(user: User): boolean;
237
237
  export function tenantRelationshipsGetByDomain(loggedInuser: User, tenant: Tenant, instance: IPublicClientApplication, debug: boolean): boolean;
238
238
  export function tenantRelationshipsGetById(user: User, ii: InitInfo, instance: IPublicClientApplication, tasks: TaskArray, debug: boolean): boolean;
package/index.ts CHANGED
@@ -391,7 +391,6 @@ export class InitInfo {
391
391
  export type TaskType = "initialization" |
392
392
  "authenticate user" |
393
393
  "reload React" |
394
- "PUT tenant" |
395
394
  "GET tenant details" |
396
395
  "POST config init" |
397
396
  "GET workspaces" |
@@ -822,7 +821,7 @@ export class BatchArray {
822
821
  this.pb_increment = 1;
823
822
  this.pb_idle = 0;
824
823
  this.pb_idleMax = 0;
825
- setIdleText(`No updates seen for ${this.pb_idle} seconds. [max idle: ${this.pb_idleMax}]`);
824
+ setIdleText(`No updates seen for ${this.pb_idle} seconds. [max idle: ${this.pb_idleMax}/60]`);
826
825
  this.pb_timer = setInterval(() => {
827
826
  // if signalR has finished the sync, stop the timer
828
827
  if (this.milestoneArray.milestones[0].Write != null) {
@@ -833,10 +832,10 @@ export class BatchArray {
833
832
  setIdleText(`Complete. [max idle: ${this.pb_idleMax}]`);
834
833
  }
835
834
  else {
836
- // if we've gone 30 seconds without a signalR message, finish the sync
835
+ // if we've gone 60 seconds without a signalR message, finish the sync
837
836
  this.pb_idle = this.pb_idle + 1;
838
837
  this.pb_idleMax = Math.max(this.pb_idle, this.pb_idleMax);
839
- setIdleText(`No updates seen for ${this.pb_idle} seconds. [max idle: ${this.pb_idleMax}]`);
838
+ setIdleText(`No updates seen for ${this.pb_idle} seconds. [max idle: ${this.pb_idleMax}/60]`);
840
839
  if (this.pb_idle >= 60) {
841
840
  clearInterval(this.pb_timer);
842
841
  this.pb_timer = null;
@@ -916,11 +915,13 @@ export class BatchArray {
916
915
  let bTotalCount = statskeys[j].endsWith("TotalCount");
917
916
  let bCurrentCount = statskeys[j].endsWith("CurrentCount");
918
917
  let bDeferredCount = statskeys[j].endsWith("DeferredCount");
918
+ let bRescheduledCount = statskeys[j].endsWith("RescheduledCount");
919
919
  if (statskeys[j].startsWith("Reader")) {
920
920
  // parse tid from Reader key
921
921
  let tidRegexp = /Reader\/TID:(.+)\/TotalCount/;
922
922
  if (bCurrentCount) tidRegexp = /Reader\/TID:(.+)\/CurrentCount/;
923
923
  if (bDeferredCount) tidRegexp = /Reader\/TID:(.+)\/DeferredCount/;
924
+ if (bRescheduledCount) tidRegexp = /Reader\/TID:(.+)\/RescheduledCount/;
924
925
  let matchTID = statskeys[j].match(tidRegexp);
925
926
  if (matchTID == null) {
926
927
  console.log(`tid not found in ${statskeys[j]}.`);
@@ -945,6 +946,7 @@ export class BatchArray {
945
946
  let tidRegexp = /Writer\/TID:(.+)\/TotalCount/;
946
947
  if (bCurrentCount) tidRegexp = /Writer\/TID:(.+)\/CurrentCount/;
947
948
  if (bDeferredCount) tidRegexp = /Writer\/TID:(.+)\/DeferredCount/;
949
+ if (bRescheduledCount) tidRegexp = /Writer\/TID:(.+)\/RescheduledCount/;
948
950
  let matchTID = statskeys[j].match(tidRegexp);
949
951
  if (matchTID == null) {
950
952
  console.log(`tid not found in ${statskeys[j]}.`);
@@ -968,7 +970,7 @@ export class BatchArray {
968
970
  writerNode.written = Math.max(Number(statsvalues[j]), writerNode.written);
969
971
  console.log(`----- ${writerNode.name} Total Written: ${writerNode.written}`);
970
972
  }
971
- else if (bDeferredCount) {
973
+ else if (bDeferredCount || bRescheduledCount) {
972
974
  writerNode.deferred = Math.max(Number(statsvalues[j]), writerNode.deferred);
973
975
  console.log(`----- ${writerNode.name} Total Deferred: ${writerNode.deferred}`);
974
976
  }
@@ -1181,6 +1183,9 @@ export function signIn(user: User, tasks: TaskArray): void {
1181
1183
  }
1182
1184
  export function signInIncrementally(user: User, scope: string): void {
1183
1185
  if (user.oid == "1") return;
1186
+ //
1187
+ // for delegated permissions, we can use the Microsoft Identity Web Account Controller Challenge method
1188
+ //
1184
1189
  let tenantURL: string = window.location.href;
1185
1190
  tenantURL += "MicrosoftIdentity/Account/Challenge";
1186
1191
  let url: URL = new URL(tenantURL);
@@ -1190,6 +1195,31 @@ export function signInIncrementally(user: User, scope: string): void {
1190
1195
  url.searchParams.append("loginHint", user.mail);
1191
1196
  window.location.assign(url.href);
1192
1197
  }
1198
+ export function requestAdminConsent(user: User, scope: string): void {
1199
+ if (user.oid == "1") return;
1200
+ //
1201
+ // for app permissions (app roles) we must use the /.default scope for admin consent
1202
+ // https://learn.microsoft.com/EN-US/azure/active-directory/develop/v2-admin-consent#:~:text=In%20order%20to%20request%20app%20permissions%2C%20you%20must%20use%20the%20/.default%20value.
1203
+ // https://learn.microsoft.com/en-us/answers/questions/431784/how-to-grant-application-permissions-with-dynamic
1204
+ //
1205
+ // this means that, if we want to be granular about SyncReader vs. SyncWriter permissions, we must have separate Applications
1206
+ // for now, we request the /.default scope whenever any of the SyncReader or SyncWriter permissions are requested
1207
+ //
1208
+ // trying to use the Challenge endpoint for app permissions, setting this scope caused the call to quietly fail without error
1209
+ // scope = "63100afe-506e-4bb2-8ff7-d8d5ab373129/.default";
1210
+ //
1211
+ // thereforce, we are assuming that, for app permissions (app roles), the Microsoft Identity Web Challenge endpoint does not work and we need to perform our own redirect to the admin consent endpoint
1212
+ // https://learn.microsoft.com/EN-US/azure/active-directory/develop/scopes-oidc#client-credentials-grant-flow-and-default
1213
+ // https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#request-the-permissions-from-a-directory-admin
1214
+ //
1215
+ let adminConsentURL: string = "https://login.microsoftonline.com/";
1216
+ adminConsentURL += user.tid;
1217
+ adminConsentURL += "/adminconsent";
1218
+ let url: URL = new URL(adminConsentURL);
1219
+ url.searchParams.append("client_id", "63100afe-506e-4bb2-8ff7-d8d5ab373129");
1220
+ url.searchParams.append("redirectUri", window.location.origin);
1221
+ window.location.assign(url.href);
1222
+ }
1193
1223
  export async function signOut(user: User): Promise<boolean>{
1194
1224
  if (user.oid == "1") return;
1195
1225
  // set logout_hint in the .NET session for streamlined logout
@@ -1557,7 +1587,7 @@ function processReturnedAdmins(workspace: Workspace, ii: InitInfo, returnedAdmin
1557
1587
  }
1558
1588
  // refresh all the data available from the server
1559
1589
  user.oid = item.userId ? item.userId : item.email;
1560
- user.name = item.firstName;
1590
+ user.name = item.firstName ?? user.name;
1561
1591
  user.mail = item.email;
1562
1592
  user.tid = item.tenantId;
1563
1593
  // ensure this workspace tracks this user
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mindline/sync",
3
3
  "type": "module",
4
- "version": "1.0.46",
4
+ "version": "1.0.49",
5
5
  "types": "index.d.ts",
6
6
  "exports": "./index.ts",
7
7
  "description": "sync is a node.js package encapsulating javscript classes required for configuring Mindline sync service.",
package/tasks.ts CHANGED
@@ -26,14 +26,6 @@ const data: any[] = [
26
26
  },
27
27
  {
28
28
  id: 4,
29
- task: "PUT tenant",
30
- start: "1970-01-01T00:00:00",
31
- end: "1970-01-01T00:00:00",
32
- expected: "0:01",
33
- status: "not started"
34
- },
35
- {
36
- id: 5,
37
29
  task: "GET tenant details",
38
30
  start: "1970-01-01T00:00:00",
39
31
  end: "1970-01-01T00:00:00",
@@ -41,7 +33,7 @@ const data: any[] = [
41
33
  status: "not started"
42
34
  },
43
35
  {
44
- id: 6,
36
+ id: 5,
45
37
  task: "POST config init",
46
38
  start: "1970-01-01T00:00:00",
47
39
  end: "1970-01-01T00:00:00",
@@ -49,7 +41,7 @@ const data: any[] = [
49
41
  status: "not started"
50
42
  },
51
43
  {
52
- id: 7,
44
+ id: 6,
53
45
  task: "GET workspaces",
54
46
  start: "1970-01-01T00:00:00",
55
47
  end: "1970-01-01T00:00:00",