@mindline/sync 1.0.113 → 1.0.114

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindline/sync",
3
- "version": "1.0.113",
3
+ "version": "1.0.114",
4
4
  "description": "sync is a node.js package encapsulating JavaScript classes required for configuring Mindline sync service.",
5
5
  "main": "dist/sync.es.js",
6
6
  "types": "dist/index.d.ts",
package/src/api-client.ts CHANGED
@@ -11,6 +11,12 @@ interface ApiResponse<T> {
11
11
  data?: T;
12
12
  error: string;
13
13
  success: boolean;
14
+ authChallenge?: {
15
+ code: string;
16
+ scopes: string[];
17
+ claims?: string;
18
+ message?: string;
19
+ };
14
20
  }
15
21
 
16
22
  // Backend DTOs (match the C# DTOs)
@@ -104,6 +110,17 @@ export async function groupsGet(groupSearchString: string): Promise<{ groups: Gr
104
110
  });
105
111
 
106
112
  if (!response.ok) {
113
+ // If backend indicates re-auth/consent is required, propagate a typed error.
114
+ if (response.status === 401) {
115
+ try {
116
+ const apiResponse: ApiResponse<GroupsResponseDto> = await response.json();
117
+ if (apiResponse?.authChallenge?.code) {
118
+ return { groups: [], error: `AUTH_REQUIRED:${apiResponse.authChallenge.code}` };
119
+ }
120
+ } catch {
121
+ // fallthrough
122
+ }
123
+ }
107
124
  return { groups: [], error: `${response.status}: Failed to retrieve groups` };
108
125
  }
109
126
 
@@ -149,6 +166,16 @@ export async function oauth2PermissionGrantsGet(
149
166
  });
150
167
 
151
168
  if (!response.ok) {
169
+ if (response.status === 401) {
170
+ try {
171
+ const apiResponse: ApiResponse<OAuth2PermissionGrantDto> = await response.json();
172
+ if (apiResponse?.authChallenge?.code) {
173
+ return { grants: null, id: null, error: `AUTH_REQUIRED:${apiResponse.authChallenge.code}` };
174
+ }
175
+ } catch {
176
+ // fallthrough
177
+ }
178
+ }
152
179
  return { grants: null, id: null, error: `${response.status}: Failed to retrieve permission grants` };
153
180
  }
154
181
 
@@ -190,6 +217,10 @@ export async function oauth2PermissionGrantsSet(id: string, scopes: string): Pro
190
217
  });
191
218
 
192
219
  if (!response.ok) {
220
+ if (response.status === 401) {
221
+ // Caller will re-auth on next operation; log for debugging.
222
+ console.warn(`oauth2PermissionGrantsSet: auth required (401)`);
223
+ }
193
224
  console.error(`oauth2PermissionGrantsSet: PATCH failed with status ${response.status}`);
194
225
  return false;
195
226
  }
@@ -227,6 +258,16 @@ export async function servicePrincipalGet(appid: string): Promise<{ spid: string
227
258
  });
228
259
 
229
260
  if (!response.ok) {
261
+ if (response.status === 401) {
262
+ try {
263
+ const apiResponse: ApiResponse<ServicePrincipalDto> = await response.json();
264
+ if (apiResponse?.authChallenge?.code) {
265
+ return { spid: '', error: `AUTH_REQUIRED:${apiResponse.authChallenge.code}` };
266
+ }
267
+ } catch {
268
+ // fallthrough
269
+ }
270
+ }
230
271
  return { spid: '', error: `${response.status}: Failed to retrieve service principal` };
231
272
  }
232
273
 
@@ -260,6 +301,16 @@ export async function usersGet(userSearchString?: string): Promise<{ users: stri
260
301
  });
261
302
 
262
303
  if (!response.ok) {
304
+ if (response.status === 401) {
305
+ try {
306
+ const apiResponse: ApiResponse<UsersResponseDto> = await response.json();
307
+ if (apiResponse?.authChallenge?.code) {
308
+ return { users: [], error: `AUTH_REQUIRED:${apiResponse.authChallenge.code}` };
309
+ }
310
+ } catch {
311
+ // fallthrough
312
+ }
313
+ }
263
314
  return { users: [], error: `${response.status}: Failed to retrieve users` };
264
315
  }
265
316
 
package/src/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { IPublicClientApplication } from "@azure/msal-browser";
2
2
  declare module "@mindline/sync" {
3
3
  export function sum(a: number, b: number): number;
4
4
  export function helloNpm(): string;
5
+ export function isAuthRefreshRequired(error: string): boolean;
5
6
  export function getSyncVersion(): string;
6
7
 
7
8
  export class APIResult<T = any> {
package/src/index.ts CHANGED
@@ -19,6 +19,30 @@ export function sum(a: number, b: number): number {
19
19
  export function helloNpm(): string {
20
20
  return "hello NPM";
21
21
  }
22
+
23
+ /**
24
+ * Returns true if an error string indicates the user needs to re-authenticate (interactive sign-in)
25
+ * before retrying a request.
26
+ *
27
+ * This is intentionally based on string matching because:
28
+ * - Some callers only have an `error: string` surface (legacy API shape)
29
+ * - The backend proxy can return plain 401 responses or Microsoft.Identity.Web error text
30
+ */
31
+ export function isAuthRefreshRequired(error: string): boolean {
32
+ if (!error) return false;
33
+
34
+ const normalized = error.toLowerCase();
35
+
36
+ // AUTH_REQUIRED is an explicit marker emitted by the proxy api-client
37
+ // 401 is often surfaced as "401: ..." by callers
38
+ // IDW10502 is a common MIW token acquisition failure marker
39
+ return (
40
+ error.startsWith("AUTH_REQUIRED") ||
41
+ error.startsWith("401") ||
42
+ error.includes("IDW10502") ||
43
+ normalized.includes("unauthorized")
44
+ );
45
+ }
22
46
  // main application exports
23
47
  declare const __SYNC_VERSION__: string
24
48
  export function getSyncVersion(): string {