@nauth-toolkit/client-angular 0.1.57 → 0.1.59

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.
@@ -29,6 +29,37 @@ export class AngularHttpAdapter {
29
29
  constructor(http) {
30
30
  this.http = http;
31
31
  }
32
+ /**
33
+ * Safely parse a JSON response body.
34
+ *
35
+ * Angular's fetch backend (`withFetch()`) will throw a raw `SyntaxError` if
36
+ * `responseType: 'json'` is used and the backend returns HTML (common for
37
+ * proxies, 502 pages, SSR fallbacks, or misrouted requests).
38
+ *
39
+ * To avoid crashing consumer apps, we always request as text and then parse
40
+ * JSON only when the response actually looks like JSON.
41
+ *
42
+ * @param bodyText - Raw response body as text
43
+ * @param contentType - Content-Type header value (if available)
44
+ * @returns Parsed JSON value (unknown)
45
+ * @throws {SyntaxError} When body is non-empty but not valid JSON
46
+ */
47
+ parseJsonBody(bodyText, contentType) {
48
+ const trimmed = bodyText.trim();
49
+ if (!trimmed)
50
+ return null;
51
+ // If it's clearly HTML, never attempt JSON.parse (some proxies mislabel Content-Type).
52
+ if (trimmed.startsWith('<')) {
53
+ return bodyText;
54
+ }
55
+ const looksLikeJson = trimmed.startsWith('{') || trimmed.startsWith('[');
56
+ const isJsonContentType = typeof contentType === 'string' && contentType.toLowerCase().includes('application/json');
57
+ if (!looksLikeJson && !isJsonContentType) {
58
+ // Return raw text when it doesn't look like JSON (e.g., HTML error pages).
59
+ return bodyText;
60
+ }
61
+ return JSON.parse(trimmed);
62
+ }
32
63
  /**
33
64
  * Execute HTTP request using Angular's HttpClient.
34
65
  *
@@ -38,29 +69,40 @@ export class AngularHttpAdapter {
38
69
  */
39
70
  async request(config) {
40
71
  try {
41
- // Use Angular's HttpClient - goes through ALL interceptors
42
- const data = await firstValueFrom(this.http.request(config.method, config.url, {
72
+ // Use Angular's HttpClient - goes through ALL interceptors.
73
+ // IMPORTANT: Use responseType 'text' to avoid raw JSON.parse crashes when
74
+ // the backend returns HTML (seen in some proxy/SSR/misroute setups).
75
+ const res = await firstValueFrom(this.http.request(config.method, config.url, {
43
76
  body: config.body,
44
77
  headers: config.headers,
45
78
  withCredentials: config.credentials === 'include',
46
- observe: 'body', // Only return body data
79
+ observe: 'response',
80
+ responseType: 'text',
47
81
  }));
82
+ const contentType = res.headers?.get('content-type');
83
+ const parsed = this.parseJsonBody(res.body ?? '', contentType);
48
84
  return {
49
- data,
50
- status: 200, // HttpClient only returns data on success
51
- headers: {}, // Can extract from observe: 'response' if needed
85
+ data: parsed,
86
+ status: res.status,
87
+ headers: {}, // Reserved for future header passthrough if needed
52
88
  };
53
89
  }
54
90
  catch (error) {
55
91
  if (error instanceof HttpErrorResponse) {
56
- // Convert Angular's HttpErrorResponse to NAuthClientError
57
- const errorData = error.error || {};
58
- const code = typeof errorData['code'] === 'string' ? errorData.code : NAuthErrorCode.INTERNAL_ERROR;
92
+ // Convert Angular's HttpErrorResponse to NAuthClientError.
93
+ // When using responseType 'text', `error.error` is typically a string.
94
+ const contentType = error.headers?.get('content-type') ?? null;
95
+ const rawBody = typeof error.error === 'string' ? error.error : '';
96
+ const parsedError = this.parseJsonBody(rawBody, contentType);
97
+ const errorData = typeof parsedError === 'object' && parsedError !== null ? parsedError : {};
98
+ const code = typeof errorData['code'] === 'string' ? errorData['code'] : NAuthErrorCode.INTERNAL_ERROR;
59
99
  const message = typeof errorData['message'] === 'string'
60
- ? errorData.message
61
- : error.message || `Request failed with status ${error.status}`;
62
- const timestamp = typeof errorData['timestamp'] === 'string' ? errorData.timestamp : undefined;
63
- const details = errorData['details'];
100
+ ? errorData['message']
101
+ : typeof parsedError === 'string' && parsedError.trim()
102
+ ? parsedError
103
+ : error.message || `Request failed with status ${error.status}`;
104
+ const timestamp = typeof errorData['timestamp'] === 'string' ? errorData['timestamp'] : undefined;
105
+ const details = typeof errorData['details'] === 'object' ? errorData['details'] : undefined;
64
106
  throw new NAuthClientError(code, message, {
65
107
  statusCode: error.status,
66
108
  timestamp,
@@ -68,8 +110,12 @@ export class AngularHttpAdapter {
68
110
  isNetworkError: error.status === 0, // Network error (no response from server)
69
111
  });
70
112
  }
71
- // Re-throw non-HTTP errors
72
- throw error;
113
+ // Re-throw non-HTTP errors as an SDK error so consumers don't see raw parser crashes.
114
+ const message = error instanceof Error ? error.message : 'Unknown error';
115
+ throw new NAuthClientError(NAuthErrorCode.INTERNAL_ERROR, message, {
116
+ statusCode: 0,
117
+ isNetworkError: true,
118
+ });
73
119
  }
74
120
  }
75
121
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
@@ -78,4 +124,4 @@ export class AngularHttpAdapter {
78
124
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter, decorators: [{
79
125
  type: Injectable
80
126
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
81
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1hZGFwdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3RhbmRhbG9uZS9odHRwLWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQWMsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNyRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3RDLE9BQU8sRUFBMEMsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7OztBQUVqSDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUVILE1BQU0sT0FBTyxrQkFBa0I7SUFDQTtJQUE3QixZQUE2QixJQUFnQjtRQUFoQixTQUFJLEdBQUosSUFBSSxDQUFZO0lBQUcsQ0FBQztJQUVqRDs7Ozs7O09BTUc7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUFJLE1BQW1CO1FBQ2xDLElBQUksQ0FBQztZQUNILDJEQUEyRDtZQUMzRCxNQUFNLElBQUksR0FBRyxNQUFNLGNBQWMsQ0FDL0IsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUksTUFBTSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsR0FBRyxFQUFFO2dCQUM5QyxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7Z0JBQ2pCLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztnQkFDdkIsZUFBZSxFQUFFLE1BQU0sQ0FBQyxXQUFXLEtBQUssU0FBUztnQkFDakQsT0FBTyxFQUFFLE1BQU0sRUFBRSx3QkFBd0I7YUFDMUMsQ0FBQyxDQUNILENBQUM7WUFFRixPQUFPO2dCQUNMLElBQUk7Z0JBQ0osTUFBTSxFQUFFLEdBQUcsRUFBRSwwQ0FBMEM7Z0JBQ3ZELE9BQU8sRUFBRSxFQUFFLEVBQUUsaURBQWlEO2FBQy9ELENBQUM7UUFDSixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksS0FBSyxZQUFZLGlCQUFpQixFQUFFLENBQUM7Z0JBQ3ZDLDBEQUEwRDtnQkFDMUQsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3BDLE1BQU0sSUFBSSxHQUNSLE9BQU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUUsU0FBUyxDQUFDLElBQXVCLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUM7Z0JBQzdHLE1BQU0sT0FBTyxHQUNYLE9BQU8sU0FBUyxDQUFDLFNBQVMsQ0FBQyxLQUFLLFFBQVE7b0JBQ3RDLENBQUMsQ0FBRSxTQUFTLENBQUMsT0FBa0I7b0JBQy9CLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxJQUFJLDhCQUE4QixLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3BFLE1BQU0sU0FBUyxHQUFHLE9BQU8sU0FBUyxDQUFDLFdBQVcsQ0FBQyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO2dCQUMvRixNQUFNLE9BQU8sR0FBRyxTQUFTLENBQUMsU0FBUyxDQUF3QyxDQUFDO2dCQUU1RSxNQUFNLElBQUksZ0JBQWdCLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRTtvQkFDeEMsVUFBVSxFQUFFLEtBQUssQ0FBQyxNQUFNO29CQUN4QixTQUFTO29CQUNULE9BQU87b0JBQ1AsY0FBYyxFQUFFLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLDBDQUEwQztpQkFDL0UsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUVELDJCQUEyQjtZQUMzQixNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO3dHQW5EVSxrQkFBa0I7NEdBQWxCLGtCQUFrQjs7NEZBQWxCLGtCQUFrQjtrQkFEOUIsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEh0dHBDbGllbnQsIEh0dHBFcnJvclJlc3BvbnNlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgZmlyc3RWYWx1ZUZyb20gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEh0dHBBZGFwdGVyLCBIdHRwUmVxdWVzdCwgSHR0cFJlc3BvbnNlLCBOQXV0aENsaWVudEVycm9yLCBOQXV0aEVycm9yQ29kZSB9IGZyb20gJ0BuYXV0aC10b29sa2l0L2NsaWVudCc7XG5cbi8qKlxuICogSFRUUCBhZGFwdGVyIGZvciBBbmd1bGFyIHVzaW5nIEh0dHBDbGllbnQuXG4gKlxuICogVGhpcyBhZGFwdGVyOlxuICogLSBVc2VzIEFuZ3VsYXIncyBIdHRwQ2xpZW50IGZvciBhbGwgcmVxdWVzdHNcbiAqIC0gV29ya3Mgd2l0aCBBbmd1bGFyJ3MgSFRUUCBpbnRlcmNlcHRvcnMgKGluY2x1ZGluZyBhdXRoSW50ZXJjZXB0b3IpXG4gKiAtIEF1dG8tcHJvdmlkZWQgdmlhIEFuZ3VsYXIgREkgKHByb3ZpZGVkSW46ICdyb290JylcbiAqIC0gQ29udmVydHMgSHR0cENsaWVudCByZXNwb25zZXMgdG8gSHR0cFJlc3BvbnNlIGZvcm1hdFxuICogLSBDb252ZXJ0cyBIdHRwRXJyb3JSZXNwb25zZSB0byBOQXV0aENsaWVudEVycm9yXG4gKlxuICogVXNlcnMgZG9uJ3QgbmVlZCB0byBjb25maWd1cmUgdGhpcyBtYW51YWxseSAtIGl0J3MgYXV0b21hdGljYWxseVxuICogaW5qZWN0ZWQgd2hlbiB1c2luZyBBdXRoU2VydmljZSBpbiBBbmd1bGFyIGFwcHMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEF1dG9tYXRpYyB1c2FnZSAobm8gbWFudWFsIHNldHVwIG5lZWRlZClcbiAqIC8vIEF1dGhTZXJ2aWNlIGF1dG9tYXRpY2FsbHkgaW5qZWN0cyBBbmd1bGFySHR0cEFkYXB0ZXJcbiAqIGNvbnN0cnVjdG9yKHByaXZhdGUgYXV0aDogQXV0aFNlcnZpY2UpIHt9XG4gKiBgYGBcbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEFuZ3VsYXJIdHRwQWRhcHRlciBpbXBsZW1lbnRzIEh0dHBBZGFwdGVyIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBodHRwOiBIdHRwQ2xpZW50KSB7fVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlIEhUVFAgcmVxdWVzdCB1c2luZyBBbmd1bGFyJ3MgSHR0cENsaWVudC5cbiAgICpcbiAgICogQHBhcmFtIGNvbmZpZyAtIFJlcXVlc3QgY29uZmlndXJhdGlvblxuICAgKiBAcmV0dXJucyBSZXNwb25zZSB3aXRoIHBhcnNlZCBkYXRhXG4gICAqIEB0aHJvd3MgTkF1dGhDbGllbnRFcnJvciBpZiByZXF1ZXN0IGZhaWxzXG4gICAqL1xuICBhc3luYyByZXF1ZXN0PFQ+KGNvbmZpZzogSHR0cFJlcXVlc3QpOiBQcm9taXNlPEh0dHBSZXNwb25zZTxUPj4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBVc2UgQW5ndWxhcidzIEh0dHBDbGllbnQgLSBnb2VzIHRocm91Z2ggQUxMIGludGVyY2VwdG9yc1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGZpcnN0VmFsdWVGcm9tKFxuICAgICAgICB0aGlzLmh0dHAucmVxdWVzdDxUPihjb25maWcubWV0aG9kLCBjb25maWcudXJsLCB7XG4gICAgICAgICAgYm9keTogY29uZmlnLmJvZHksXG4gICAgICAgICAgaGVhZGVyczogY29uZmlnLmhlYWRlcnMsXG4gICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiBjb25maWcuY3JlZGVudGlhbHMgPT09ICdpbmNsdWRlJyxcbiAgICAgICAgICBvYnNlcnZlOiAnYm9keScsIC8vIE9ubHkgcmV0dXJuIGJvZHkgZGF0YVxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGRhdGEsXG4gICAgICAgIHN0YXR1czogMjAwLCAvLyBIdHRwQ2xpZW50IG9ubHkgcmV0dXJucyBkYXRhIG9uIHN1Y2Nlc3NcbiAgICAgICAgaGVhZGVyczoge30sIC8vIENhbiBleHRyYWN0IGZyb20gb2JzZXJ2ZTogJ3Jlc3BvbnNlJyBpZiBuZWVkZWRcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEh0dHBFcnJvclJlc3BvbnNlKSB7XG4gICAgICAgIC8vIENvbnZlcnQgQW5ndWxhcidzIEh0dHBFcnJvclJlc3BvbnNlIHRvIE5BdXRoQ2xpZW50RXJyb3JcbiAgICAgICAgY29uc3QgZXJyb3JEYXRhID0gZXJyb3IuZXJyb3IgfHwge307XG4gICAgICAgIGNvbnN0IGNvZGUgPVxuICAgICAgICAgIHR5cGVvZiBlcnJvckRhdGFbJ2NvZGUnXSA9PT0gJ3N0cmluZycgPyAoZXJyb3JEYXRhLmNvZGUgYXMgTkF1dGhFcnJvckNvZGUpIDogTkF1dGhFcnJvckNvZGUuSU5URVJOQUxfRVJST1I7XG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPVxuICAgICAgICAgIHR5cGVvZiBlcnJvckRhdGFbJ21lc3NhZ2UnXSA9PT0gJ3N0cmluZydcbiAgICAgICAgICAgID8gKGVycm9yRGF0YS5tZXNzYWdlIGFzIHN0cmluZylcbiAgICAgICAgICAgIDogZXJyb3IubWVzc2FnZSB8fCBgUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgJHtlcnJvci5zdGF0dXN9YDtcbiAgICAgICAgY29uc3QgdGltZXN0YW1wID0gdHlwZW9mIGVycm9yRGF0YVsndGltZXN0YW1wJ10gPT09ICdzdHJpbmcnID8gZXJyb3JEYXRhLnRpbWVzdGFtcCA6IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgZGV0YWlscyA9IGVycm9yRGF0YVsnZGV0YWlscyddIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkO1xuXG4gICAgICAgIHRocm93IG5ldyBOQXV0aENsaWVudEVycm9yKGNvZGUsIG1lc3NhZ2UsIHtcbiAgICAgICAgICBzdGF0dXNDb2RlOiBlcnJvci5zdGF0dXMsXG4gICAgICAgICAgdGltZXN0YW1wLFxuICAgICAgICAgIGRldGFpbHMsXG4gICAgICAgICAgaXNOZXR3b3JrRXJyb3I6IGVycm9yLnN0YXR1cyA9PT0gMCwgLy8gTmV0d29yayBlcnJvciAobm8gcmVzcG9uc2UgZnJvbSBzZXJ2ZXIpXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICAvLyBSZS10aHJvdyBub24tSFRUUCBlcnJvcnNcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxufVxuIl19
127
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1hZGFwdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3RhbmRhbG9uZS9odHRwLWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQWMsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNyRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3RDLE9BQU8sRUFBMEMsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7OztBQUVqSDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUVILE1BQU0sT0FBTyxrQkFBa0I7SUFDQTtJQUE3QixZQUE2QixJQUFnQjtRQUFoQixTQUFJLEdBQUosSUFBSSxDQUFZO0lBQUcsQ0FBQztJQUVqRDs7Ozs7Ozs7Ozs7Ozs7T0FjRztJQUNLLGFBQWEsQ0FBQyxRQUFnQixFQUFFLFdBQTBCO1FBQ2hFLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU8sSUFBSSxDQUFDO1FBRTFCLHVGQUF1RjtRQUN2RixJQUFJLE9BQU8sQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM1QixPQUFPLFFBQVEsQ0FBQztRQUNsQixDQUFDO1FBRUQsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pFLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxXQUFXLEtBQUssUUFBUSxJQUFJLFdBQVcsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUVwSCxJQUFJLENBQUMsYUFBYSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZ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LENBQUM7Z0JBRXpILE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFO29CQUN4QyxVQUFVLEVBQUUsS0FBSyxDQUFDLE1BQU07b0JBQ3hCLFNBQVM7b0JBQ1QsT0FBTztvQkFDUCxjQUFjLEVBQUUsS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsMENBQTBDO2lCQUMvRSxDQUFDLENBQUM7WUFDTCxDQUFDO1lBRUQsc0ZBQXNGO1lBQ3RGLE1BQU0sT0FBTyxHQUFHLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQztZQUN6RSxNQUFNLElBQUksZ0JBQWdCLENBQUMsY0FBYyxDQUFDLGNBQWMsRUFBRSxPQUFPLEVBQUU7Z0JBQ2pFLFVBQVUsRUFBRSxDQUFDO2dCQUNiLGNBQWMsRUFBRSxJQUFJO2FBQ3JCLENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDO3dHQXRHVSxrQkFBa0I7NEdBQWxCLGtCQUFrQjs7NEZBQWxCLGtCQUFrQjtrQkFEOUIsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEh0dHBDbGllbnQsIEh0dHBFcnJvclJlc3BvbnNlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgZmlyc3RWYWx1ZUZyb20gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEh0dHBBZGFwdGVyLCBIdHRwUmVxdWVzdCwgSHR0cFJlc3BvbnNlLCBOQXV0aENsaWVudEVycm9yLCBOQXV0aEVycm9yQ29kZSB9IGZyb20gJ0BuYXV0aC10b29sa2l0L2NsaWVudCc7XG5cbi8qKlxuICogSFRUUCBhZGFwdGVyIGZvciBBbmd1bGFyIHVzaW5nIEh0dHBDbGllbnQuXG4gKlxuICogVGhpcyBhZGFwdGVyOlxuICogLSBVc2VzIEFuZ3VsYXIncyBIdHRwQ2xpZW50IGZvciBhbGwgcmVxdWVzdHNcbiAqIC0gV29ya3Mgd2l0aCBBbmd1bGFyJ3MgSFRUUCBpbnRlcmNlcHRvcnMgKGluY2x1ZGluZyBhdXRoSW50ZXJjZXB0b3IpXG4gKiAtIEF1dG8tcHJvdmlkZWQgdmlhIEFuZ3VsYXIgREkgKHByb3ZpZGVkSW46ICdyb290JylcbiAqIC0gQ29udmVydHMgSHR0cENsaWVudCByZXNwb25zZXMgdG8gSHR0cFJlc3BvbnNlIGZvcm1hdFxuICogLSBDb252ZXJ0cyBIdHRwRXJyb3JSZXNwb25zZSB0byBOQXV0aENsaWVudEVycm9yXG4gKlxuICogVXNlcnMgZG9uJ3QgbmVlZCB0byBjb25maWd1cmUgdGhpcyBtYW51YWxseSAtIGl0J3MgYXV0b21hdGljYWxseVxuICogaW5qZWN0ZWQgd2hlbiB1c2luZyBBdXRoU2VydmljZSBpbiBBbmd1bGFyIGFwcHMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEF1dG9tYXRpYyB1c2FnZSAobm8gbWFudWFsIHNldHVwIG5lZWRlZClcbiAqIC8vIEF1dGhTZXJ2aWNlIGF1dG9tYXRpY2FsbHkgaW5qZWN0cyBBbmd1bGFySHR0cEFkYXB0ZXJcbiAqIGNvbnN0cnVjdG9yKHByaXZhdGUgYXV0aDogQXV0aFNlcnZpY2UpIHt9XG4gKiBgYGBcbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEFuZ3VsYXJIdHRwQWRhcHRlciBpbXBsZW1lbnRzIEh0dHBBZGFwdGVyIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBodHRwOiBIdHRwQ2xpZW50KSB7fVxuXG4gIC8qKlxuICAgKiBTYWZlbHkgcGFyc2UgYSBKU09OIHJlc3BvbnNlIGJvZHkuXG4gICAqXG4gICAqIEFuZ3VsYXIncyBmZXRjaCBiYWNrZW5kIChgd2l0aEZldGNoKClgKSB3aWxsIHRocm93IGEgcmF3IGBTeW50YXhFcnJvcmAgaWZcbiAgICogYHJlc3BvbnNlVHlwZTogJ2pzb24nYCBpcyB1c2VkIGFuZCB0aGUgYmFja2VuZCByZXR1cm5zIEhUTUwgKGNvbW1vbiBmb3JcbiAgICogcHJveGllcywgNTAyIHBhZ2VzLCBTU1IgZmFsbGJhY2tzLCBvciBtaXNyb3V0ZWQgcmVxdWVzdHMpLlxuICAgKlxuICAgKiBUbyBhdm9pZCBjcmFzaGluZyBjb25zdW1lciBhcHBzLCB3ZSBhbHdheXMgcmVxdWVzdCBhcyB0ZXh0IGFuZCB0aGVuIHBhcnNlXG4gICAqIEpTT04gb25seSB3aGVuIHRoZSByZXNwb25zZSBhY3R1YWxseSBsb29rcyBsaWtlIEpTT04uXG4gICAqXG4gICAqIEBwYXJhbSBib2R5VGV4dCAtIFJhdyByZXNwb25zZSBib2R5IGFzIHRleHRcbiAgICogQHBhcmFtIGNvbnRlbnRUeXBlIC0gQ29udGVudC1UeXBlIGhlYWRlciB2YWx1ZSAoaWYgYXZhaWxhYmxlKVxuICAgKiBAcmV0dXJucyBQYXJzZWQgSlNPTiB2YWx1ZSAodW5rbm93bilcbiAgICogQHRocm93cyB7U3ludGF4RXJyb3J9IFdoZW4gYm9keSBpcyBub24tZW1wdHkgYnV0IG5vdCB2YWxpZCBKU09OXG4gICAqL1xuICBwcml2YXRlIHBhcnNlSnNvbkJvZHkoYm9keVRleHQ6IHN0cmluZywgY29udGVudFR5cGU6IHN0cmluZyB8IG51bGwpOiB1bmtub3duIHtcbiAgICBjb25zdCB0cmltbWVkID0gYm9keVRleHQudHJpbSgpO1xuICAgIGlmICghdHJpbW1lZCkgcmV0dXJuIG51bGw7XG5cbiAgICAvLyBJZiBpdCdzIGNsZWFybHkgSFRNTCwgbmV2ZXIgYXR0ZW1wdCBKU09OLnBhcnNlIChzb21lIHByb3hpZXMgbWlzbGFiZWwgQ29udGVudC1UeXBlKS5cbiAgICBpZiAodHJpbW1lZC5zdGFydHNXaXRoKCc8JykpIHtcbiAgICAgIHJldHVybiBib2R5VGV4dDtcbiAgICB9XG5cbiAgICBjb25zdCBsb29rc0xpa2VKc29uID0gdHJpbW1lZC5zdGFydHNXaXRoKCd7JykgfHwgdHJpbW1lZC5zdGFydHNXaXRoKCdbJyk7XG4gICAgY29uc3QgaXNKc29uQ29udGVudFR5cGUgPSB0eXBlb2YgY29udGVudFR5cGUgPT09ICdzdHJpbmcnICYmIGNvbnRlbnRUeXBlLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoJ2FwcGxpY2F0aW9uL2pzb24nKTtcblxuICAgIGlmICghbG9va3NMaWtlSnNvbiAmJiAhaXNKc29uQ29udGVudFR5cGUpIHtcbiAgICAgIC8vIFJldHVybiByYXcgdGV4dCB3aGVuIGl0IGRvZXNuJ3QgbG9vayBsaWtlIEpTT04gKGUuZy4sIEhUTUwgZXJyb3IgcGFnZXMpLlxuICAgICAgcmV0dXJuIGJvZHlUZXh0O1xuICAgIH1cblxuICAgIHJldHVybiBKU09OLnBhcnNlKHRyaW1tZWQpIGFzIHVua25vd247XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSBIVFRQIHJlcXVlc3QgdXNpbmcgQW5ndWxhcidzIEh0dHBDbGllbnQuXG4gICAqXG4gICAqIEBwYXJhbSBjb25maWcgLSBSZXF1ZXN0IGNvbmZpZ3VyYXRpb25cbiAgICogQHJldHVybnMgUmVzcG9uc2Ugd2l0aCBwYXJzZWQgZGF0YVxuICAgKiBAdGhyb3dzIE5BdXRoQ2xpZW50RXJyb3IgaWYgcmVxdWVzdCBmYWlsc1xuICAgKi9cbiAgYXN5bmMgcmVxdWVzdDxUPihjb25maWc6IEh0dHBSZXF1ZXN0KTogUHJvbWlzZTxIdHRwUmVzcG9uc2U8VD4+IHtcbiAgICB0cnkge1xuICAgICAgLy8gVXNlIEFuZ3VsYXIncyBIdHRwQ2xpZW50IC0gZ29lcyB0aHJvdWdoIEFMTCBpbnRlcmNlcHRvcnMuXG4gICAgICAvLyBJTVBPUlRBTlQ6IFVzZSByZXNwb25zZVR5cGUgJ3RleHQnIHRvIGF2b2lkIHJhdyBKU09OLnBhcnNlIGNyYXNoZXMgd2hlblxuICAgICAgLy8gdGhlIGJhY2tlbmQgcmV0dXJucyBIVE1MIChzZWVuIGluIHNvbWUgcHJveHkvU1NSL21pc3JvdXRlIHNldHVwcykuXG4gICAgICBjb25zdCByZXMgPSBhd2FpdCBmaXJzdFZhbHVlRnJvbShcbiAgICAgICAgdGhpcy5odHRwLnJlcXVlc3QoY29uZmlnLm1ldGhvZCwgY29uZmlnLnVybCwge1xuICAgICAgICAgIGJvZHk6IGNvbmZpZy5ib2R5LFxuICAgICAgICAgIGhlYWRlcnM6IGNvbmZpZy5oZWFkZXJzLFxuICAgICAgICAgIHdpdGhDcmVkZW50aWFsczogY29uZmlnLmNyZWRlbnRpYWxzID09PSAnaW5jbHVkZScsXG4gICAgICAgICAgb2JzZXJ2ZTogJ3Jlc3BvbnNlJyxcbiAgICAgICAgICByZXNwb25zZVR5cGU6ICd0ZXh0JyxcbiAgICAgICAgfSksXG4gICAgICApO1xuXG4gICAgICBjb25zdCBjb250ZW50VHlwZSA9IHJlcy5oZWFkZXJzPy5nZXQoJ2NvbnRlbnQtdHlwZScpO1xuICAgICAgY29uc3QgcGFyc2VkID0gdGhpcy5wYXJzZUpzb25Cb2R5KHJlcy5ib2R5ID8/ICcnLCBjb250ZW50VHlwZSk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGRhdGE6IHBhcnNlZCBhcyBULFxuICAgICAgICBzdGF0dXM6IHJlcy5zdGF0dXMsXG4gICAgICAgIGhlYWRlcnM6IHt9LCAvLyBSZXNlcnZlZCBmb3IgZnV0dXJlIGhlYWRlciBwYXNzdGhyb3VnaCBpZiBuZWVkZWRcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEh0dHBFcnJvclJlc3BvbnNlKSB7XG4gICAgICAgIC8vIENvbnZlcnQgQW5ndWxhcidzIEh0dHBFcnJvclJlc3BvbnNlIHRvIE5BdXRoQ2xpZW50RXJyb3IuXG4gICAgICAgIC8vIFdoZW4gdXNpbmcgcmVzcG9uc2VUeXBlICd0ZXh0JywgYGVycm9yLmVycm9yYCBpcyB0eXBpY2FsbHkgYSBzdHJpbmcuXG4gICAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gZXJyb3IuaGVhZGVycz8uZ2V0KCdjb250ZW50LXR5cGUnKSA/PyBudWxsO1xuICAgICAgICBjb25zdCByYXdCb2R5ID0gdHlwZW9mIGVycm9yLmVycm9yID09PSAnc3RyaW5nJyA/IGVycm9yLmVycm9yIDogJyc7XG4gICAgICAgIGNvbnN0IHBhcnNlZEVycm9yID0gdGhpcy5wYXJzZUpzb25Cb2R5KHJhd0JvZHksIGNvbnRlbnRUeXBlKTtcblxuICAgICAgICBjb25zdCBlcnJvckRhdGEgPSB0eXBlb2YgcGFyc2VkRXJyb3IgPT09ICdvYmplY3QnICYmIHBhcnNlZEVycm9yICE9PSBudWxsID8gKHBhcnNlZEVycm9yIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA6IHt9O1xuICAgICAgICBjb25zdCBjb2RlID0gdHlwZW9mIGVycm9yRGF0YVsnY29kZSddID09PSAnc3RyaW5nJyA/IChlcnJvckRhdGFbJ2NvZGUnXSBhcyBOQXV0aEVycm9yQ29kZSkgOiBOQXV0aEVycm9yQ29kZS5JTlRFUk5BTF9FUlJPUjtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9XG4gICAgICAgICAgdHlwZW9mIGVycm9yRGF0YVsnbWVzc2FnZSddID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgPyAoZXJyb3JEYXRhWydtZXNzYWdlJ10gYXMgc3RyaW5nKVxuICAgICAgICAgICAgOiB0eXBlb2YgcGFyc2VkRXJyb3IgPT09ICdzdHJpbmcnICYmIHBhcnNlZEVycm9yLnRyaW0oKVxuICAgICAgICAgICAgICA/IHBhcnNlZEVycm9yXG4gICAgICAgICAgICAgIDogZXJyb3IubWVzc2FnZSB8fCBgUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgJHtlcnJvci5zdGF0dXN9YDtcbiAgICAgICAgY29uc3QgdGltZXN0YW1wID0gdHlwZW9mIGVycm9yRGF0YVsndGltZXN0YW1wJ10gPT09ICdzdHJpbmcnID8gKGVycm9yRGF0YVsndGltZXN0YW1wJ10gYXMgc3RyaW5nKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgZGV0YWlscyA9IHR5cGVvZiBlcnJvckRhdGFbJ2RldGFpbHMnXSA9PT0gJ29iamVjdCcgPyAoZXJyb3JEYXRhWydkZXRhaWxzJ10gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pIDogdW5kZWZpbmVkO1xuXG4gICAgICAgIHRocm93IG5ldyBOQXV0aENsaWVudEVycm9yKGNvZGUsIG1lc3NhZ2UsIHtcbiAgICAgICAgICBzdGF0dXNDb2RlOiBlcnJvci5zdGF0dXMsXG4gICAgICAgICAgdGltZXN0YW1wLFxuICAgICAgICAgIGRldGFpbHMsXG4gICAgICAgICAgaXNOZXR3b3JrRXJyb3I6IGVycm9yLnN0YXR1cyA9PT0gMCwgLy8gTmV0d29yayBlcnJvciAobm8gcmVzcG9uc2UgZnJvbSBzZXJ2ZXIpXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICAvLyBSZS10aHJvdyBub24tSFRUUCBlcnJvcnMgYXMgYW4gU0RLIGVycm9yIHNvIGNvbnN1bWVycyBkb24ndCBzZWUgcmF3IHBhcnNlciBjcmFzaGVzLlxuICAgICAgY29uc3QgbWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogJ1Vua25vd24gZXJyb3InO1xuICAgICAgdGhyb3cgbmV3IE5BdXRoQ2xpZW50RXJyb3IoTkF1dGhFcnJvckNvZGUuSU5URVJOQUxfRVJST1IsIG1lc3NhZ2UsIHtcbiAgICAgICAgc3RhdHVzQ29kZTogMCxcbiAgICAgICAgaXNOZXR3b3JrRXJyb3I6IHRydWUsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -1,7 +1,7 @@
1
1
  import { inject, PLATFORM_ID } from '@angular/core';
2
2
  import { isPlatformBrowser } from '@angular/common';
3
3
  import { AuthService } from './auth.service';
4
- import { NAUTH_CLIENT_CONFIG } from './tokens';
4
+ import { NAuthClientError, NAuthErrorCode } from '@nauth-toolkit/client';
5
5
  /**
6
6
  * Social redirect callback route guard.
7
7
  *
@@ -12,8 +12,8 @@ import { NAUTH_CLIENT_CONFIG } from './tokens';
12
12
  * - `error` / `error_description` (provider errors)
13
13
  *
14
14
  * Behavior:
15
- * - If `exchangeToken` exists: exchanges it via backend and redirects to success or challenge routes.
16
- * - If no `exchangeToken`: treat as cookie-success path and redirect to success route.
15
+ * - If `exchangeToken` exists: exchanges it via backend (SDK handles navigation automatically).
16
+ * - If no `exchangeToken`: treat as cookie-success path (SDK handles navigation automatically).
17
17
  * - If `error` exists: redirects to oauthError route.
18
18
  *
19
19
  * @example
@@ -27,7 +27,6 @@ import { NAUTH_CLIENT_CONFIG } from './tokens';
27
27
  */
28
28
  export const socialRedirectCallbackGuard = async () => {
29
29
  const auth = inject(AuthService);
30
- const config = inject(NAUTH_CLIENT_CONFIG);
31
30
  const platformId = inject(PLATFORM_ID);
32
31
  const isBrowser = isPlatformBrowser(platformId);
33
32
  if (!isBrowser) {
@@ -36,13 +35,13 @@ export const socialRedirectCallbackGuard = async () => {
36
35
  const params = new URLSearchParams(window.location.search);
37
36
  const error = params.get('error');
38
37
  const exchangeToken = params.get('exchangeToken');
38
+ const router = auth.getChallengeRouter();
39
39
  // Provider error: redirect to oauthError
40
40
  if (error) {
41
- const errorUrl = config.redirects?.oauthError || '/login';
42
- window.location.replace(errorUrl);
41
+ await router.navigateToError('oauth');
43
42
  return false;
44
43
  }
45
- // No exchangeToken: cookie success path; redirect to success.
44
+ // No exchangeToken: cookie success path; hydrate then navigate to success.
46
45
  //
47
46
  // Note: we do not "activate" the callback route to avoid consumers needing to render a page.
48
47
  if (!exchangeToken) {
@@ -56,26 +55,31 @@ export const socialRedirectCallbackGuard = async () => {
56
55
  // `currentUser` is still null even though cookies were set successfully.
57
56
  try {
58
57
  await auth.getProfile();
58
+ await router.navigateToSuccess();
59
59
  }
60
- catch {
61
- const errorUrl = config.redirects?.oauthError || '/login';
62
- window.location.replace(errorUrl);
63
- return false;
60
+ catch (err) {
61
+ // Only treat auth failures (401/403) as OAuth errors
62
+ // Network errors or other issues might be temporary - still try success route
63
+ const isAuthError = err instanceof NAuthClientError &&
64
+ (err.statusCode === 401 ||
65
+ err.statusCode === 403 ||
66
+ err.code === NAuthErrorCode.AUTH_TOKEN_INVALID ||
67
+ err.code === NAuthErrorCode.AUTH_SESSION_EXPIRED ||
68
+ err.code === NAuthErrorCode.AUTH_SESSION_NOT_FOUND);
69
+ if (isAuthError) {
70
+ // Cookies weren't set properly - OAuth failed
71
+ await router.navigateToError('oauth');
72
+ }
73
+ else {
74
+ // For network errors or other issues, proceed to success route
75
+ // The auth guard will handle authentication state on the next route
76
+ await router.navigateToSuccess();
77
+ }
64
78
  }
65
- const successUrl = config.redirects?.success || '/';
66
- window.location.replace(successUrl);
67
79
  return false;
68
80
  }
69
- // Exchange token and route accordingly
70
- const response = await auth.exchangeSocialRedirect(exchangeToken);
71
- if (response.challengeName) {
72
- const challengeBase = config.redirects?.challengeBase || '/auth/challenge';
73
- const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, '-');
74
- window.location.replace(`${challengeBase}/${challengeRoute}`);
75
- return false;
76
- }
77
- const successUrl = config.redirects?.success || '/';
78
- window.location.replace(successUrl);
81
+ // Exchange token - SDK handles navigation automatically
82
+ await auth.exchangeSocialRedirect(exchangeToken);
79
83
  return false;
80
84
  };
81
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29jaWFsLXJlZGlyZWN0LWNhbGxiYWNrLmd1YXJkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3RhbmRhbG9uZS9zb2NpYWwtcmVkaXJlY3QtY2FsbGJhY2suZ3VhcmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDcEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFcEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUUvQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUNILE1BQU0sQ0FBQyxNQUFNLDJCQUEyQixHQUFrQixLQUFLLElBQXNCLEVBQUU7SUFDckYsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ2pDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBQzNDLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN2QyxNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVoRCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFJLGVBQWUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzNELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbEMsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUVsRCx5Q0FBeUM7SUFDekMsSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUNWLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxTQUFTLEVBQUUsVUFBVSxJQUFJLFFBQVEsQ0FBQztRQUMxRCxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNsQyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCw4REFBOEQ7SUFDOUQsRUFBRTtJQUNGLDZGQUE2RjtJQUM3RixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDbkIsK0VBQStFO1FBQy9FLHNEQUFzRDtRQUN0RCwrRUFBK0U7UUFDL0UsK0ZBQStGO1FBQy9GLG1GQUFtRjtRQUNuRixFQUFFO1FBQ0YscUZBQXFGO1FBQ3JGLHlFQUF5RTtRQUN6RSxJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUMxQixDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLFNBQVMsRUFBRSxVQUFVLElBQUksUUFBUSxDQUFDO1lBQzFELE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2xDLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUNELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxTQUFTLEVBQUUsT0FBTyxJQUFJLEdBQUcsQ0FBQztRQUNwRCxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNwQyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCx1Q0FBdUM7SUFDdkMsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsc0JBQXNCLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDbEUsSUFBSSxRQUFRLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDM0IsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLFNBQVMsRUFBRSxhQUFhLElBQUksaUJBQWlCLENBQUM7UUFDM0UsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQy9FLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsYUFBYSxJQUFJLGNBQWMsRUFBRSxDQUFDLENBQUM7UUFDOUQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFNBQVMsRUFBRSxPQUFPLElBQUksR0FBRyxDQUFDO0lBQ3BELE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3BDLE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgdHlwZSBDYW5BY3RpdmF0ZUZuIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLnNlcnZpY2UnO1xuaW1wb3J0IHsgTkFVVEhfQ0xJRU5UX0NPTkZJRyB9IGZyb20gJy4vdG9rZW5zJztcblxuLyoqXG4gKiBTb2NpYWwgcmVkaXJlY3QgY2FsbGJhY2sgcm91dGUgZ3VhcmQuXG4gKlxuICogVGhpcyBndWFyZCBzdXBwb3J0cyB0aGUgcmVkaXJlY3QtZmlyc3Qgc29jaWFsIGZsb3cgd2hlcmUgdGhlIGJhY2tlbmQgcmVkaXJlY3RzXG4gKiBiYWNrIHRvIHRoZSBmcm9udGVuZCB3aXRoOlxuICogLSBgYXBwU3RhdGVgIChhbHdheXMgb3B0aW9uYWwpXG4gKiAtIGBleGNoYW5nZVRva2VuYCAocHJlc2VudCBmb3IganNvbi9oeWJyaWQgZmxvd3MsIGFuZCBmb3IgY29va2llIGZsb3dzIHRoYXQgcmV0dXJuIGEgY2hhbGxlbmdlKVxuICogLSBgZXJyb3JgIC8gYGVycm9yX2Rlc2NyaXB0aW9uYCAocHJvdmlkZXIgZXJyb3JzKVxuICpcbiAqIEJlaGF2aW9yOlxuICogLSBJZiBgZXhjaGFuZ2VUb2tlbmAgZXhpc3RzOiBleGNoYW5nZXMgaXQgdmlhIGJhY2tlbmQgYW5kIHJlZGlyZWN0cyB0byBzdWNjZXNzIG9yIGNoYWxsZW5nZSByb3V0ZXMuXG4gKiAtIElmIG5vIGBleGNoYW5nZVRva2VuYDogdHJlYXQgYXMgY29va2llLXN1Y2Nlc3MgcGF0aCBhbmQgcmVkaXJlY3QgdG8gc3VjY2VzcyByb3V0ZS5cbiAqIC0gSWYgYGVycm9yYCBleGlzdHM6IHJlZGlyZWN0cyB0byBvYXV0aEVycm9yIHJvdXRlLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBzb2NpYWxSZWRpcmVjdENhbGxiYWNrR3VhcmQgfSBmcm9tICdAbmF1dGgtdG9vbGtpdC9jbGllbnQvYW5ndWxhcic7XG4gKlxuICogZXhwb3J0IGNvbnN0IHJvdXRlczogUm91dGVzID0gW1xuICogICB7IHBhdGg6ICdhdXRoL2NhbGxiYWNrJywgY2FuQWN0aXZhdGU6IFtzb2NpYWxSZWRpcmVjdENhbGxiYWNrR3VhcmRdLCBjb21wb25lbnQ6IENhbGxiYWNrQ29tcG9uZW50IH0sXG4gKiBdO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBzb2NpYWxSZWRpcmVjdENhbGxiYWNrR3VhcmQ6IENhbkFjdGl2YXRlRm4gPSBhc3luYyAoKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gIGNvbnN0IGF1dGggPSBpbmplY3QoQXV0aFNlcnZpY2UpO1xuICBjb25zdCBjb25maWcgPSBpbmplY3QoTkFVVEhfQ0xJRU5UX0NPTkZJRyk7XG4gIGNvbnN0IHBsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpO1xuICBjb25zdCBpc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3NlcihwbGF0Zm9ybUlkKTtcblxuICBpZiAoIWlzQnJvd3Nlcikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGNvbnN0IHBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XG4gIGNvbnN0IGVycm9yID0gcGFyYW1zLmdldCgnZXJyb3InKTtcbiAgY29uc3QgZXhjaGFuZ2VUb2tlbiA9IHBhcmFtcy5nZXQoJ2V4Y2hhbmdlVG9rZW4nKTtcblxuICAvLyBQcm92aWRlciBlcnJvcjogcmVkaXJlY3QgdG8gb2F1dGhFcnJvclxuICBpZiAoZXJyb3IpIHtcbiAgICBjb25zdCBlcnJvclVybCA9IGNvbmZpZy5yZWRpcmVjdHM/Lm9hdXRoRXJyb3IgfHwgJy9sb2dpbic7XG4gICAgd2luZG93LmxvY2F0aW9uLnJlcGxhY2UoZXJyb3JVcmwpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIE5vIGV4Y2hhbmdlVG9rZW46IGNvb2tpZSBzdWNjZXNzIHBhdGg7IHJlZGlyZWN0IHRvIHN1Y2Nlc3MuXG4gIC8vXG4gIC8vIE5vdGU6IHdlIGRvIG5vdCBcImFjdGl2YXRlXCIgdGhlIGNhbGxiYWNrIHJvdXRlIHRvIGF2b2lkIGNvbnN1bWVycyBuZWVkaW5nIHRvIHJlbmRlciBhIHBhZ2UuXG4gIGlmICghZXhjaGFuZ2VUb2tlbikge1xuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAvLyBDb29raWVzIG1vZGU6IGh5ZHJhdGUgdXNlciBzdGF0ZSBiZWZvcmUgcmVkaXJlY3RpbmdcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgLy8gV0hZOiBJbiBjb29raWUgZGVsaXZlcnksIHRoZSBPQXV0aCBjYWxsYmFjayBjb21wbGV0ZXMgdmlhIGJyb3dzZXIgcmVkaXJlY3RzLCBzbyB0aGUgZnJvbnRlbmRcbiAgICAvLyBkb2VzIG5vdCByZWNlaXZlIGEgSlNPTiBBdXRoUmVzcG9uc2UgdG8gcG9wdWxhdGUgdGhlIFNESydzIGNhY2hlZCBgY3VycmVudFVzZXJgLlxuICAgIC8vXG4gICAgLy8gV2l0aG91dCB0aGlzLCBzeW5jIGd1YXJkcyAoYGF1dGhHdWFyZGApIGNhbiBpbW1lZGlhdGVseSByZWRpcmVjdCB0byAvbG9naW4gYmVjYXVzZVxuICAgIC8vIGBjdXJyZW50VXNlcmAgaXMgc3RpbGwgbnVsbCBldmVuIHRob3VnaCBjb29raWVzIHdlcmUgc2V0IHN1Y2Nlc3NmdWxseS5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgYXV0aC5nZXRQcm9maWxlKCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICBjb25zdCBlcnJvclVybCA9IGNvbmZpZy5yZWRpcmVjdHM/Lm9hdXRoRXJyb3IgfHwgJy9sb2dpbic7XG4gICAgICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZShlcnJvclVybCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IHN1Y2Nlc3NVcmwgPSBjb25maWcucmVkaXJlY3RzPy5zdWNjZXNzIHx8ICcvJztcbiAgICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZShzdWNjZXNzVXJsKTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBFeGNoYW5nZSB0b2tlbiBhbmQgcm91dGUgYWNjb3JkaW5nbHlcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBhdXRoLmV4Y2hhbmdlU29jaWFsUmVkaXJlY3QoZXhjaGFuZ2VUb2tlbik7XG4gIGlmIChyZXNwb25zZS5jaGFsbGVuZ2VOYW1lKSB7XG4gICAgY29uc3QgY2hhbGxlbmdlQmFzZSA9IGNvbmZpZy5yZWRpcmVjdHM/LmNoYWxsZW5nZUJhc2UgfHwgJy9hdXRoL2NoYWxsZW5nZSc7XG4gICAgY29uc3QgY2hhbGxlbmdlUm91dGUgPSByZXNwb25zZS5jaGFsbGVuZ2VOYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvXy9nLCAnLScpO1xuICAgIHdpbmRvdy5sb2NhdGlvbi5yZXBsYWNlKGAke2NoYWxsZW5nZUJhc2V9LyR7Y2hhbGxlbmdlUm91dGV9YCk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgY29uc3Qgc3VjY2Vzc1VybCA9IGNvbmZpZy5yZWRpcmVjdHM/LnN1Y2Nlc3MgfHwgJy8nO1xuICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZShzdWNjZXNzVXJsKTtcbiAgcmV0dXJuIGZhbHNlO1xufTtcbiJdfQ==
85
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29jaWFsLXJlZGlyZWN0LWNhbGxiYWNrLmd1YXJkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3RhbmRhbG9uZS9zb2NpYWwtcmVkaXJlY3QtY2FsbGJhY2suZ3VhcmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDcEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFcEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUV6RTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUNILE1BQU0sQ0FBQyxNQUFNLDJCQUEyQixHQUFrQixLQUFLLElBQXNCLEVBQUU7SUFDckYsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ2pDLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN2QyxNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVoRCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFJLGVBQWUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzNELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbEMsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUNsRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUV6Qyx5Q0FBeUM7SUFDekMsSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUNWLE1BQU0sTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0QyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCwyRUFBMkU7SUFDM0UsRUFBRTtJQUNGLDZGQUE2RjtJQUM3RixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDbkIsK0VBQStFO1FBQy9FLHNEQUFzRDtRQUN0RCwrRUFBK0U7UUFDL0UsK0ZBQStGO1FBQy9GLG1GQUFtRjtRQUNuRixFQUFFO1FBQ0YscUZBQXFGO1FBQ3JGLHlFQUF5RTtRQUN6RSxJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUN4QixNQUFNLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ25DLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IscURBQXFEO1lBQ3JELDhFQUE4RTtZQUM5RSxNQUFNLFdBQVcsR0FDZixHQUFHLFlBQVksZ0JBQWdCO2dCQUMvQixDQUFDLEdBQUcsQ0FBQyxVQUFVLEtBQUssR0FBRztvQkFDckIsR0FBRyxDQUFDLFVBQVUsS0FBSyxHQUFHO29CQUN0QixHQUFHLENBQUMsSUFBSSxLQUFLLGNBQWMsQ0FBQyxrQkFBa0I7b0JBQzlDLEdBQUcsQ0FBQyxJQUFJLEtBQUssY0FBYyxDQUFDLG9CQUFvQjtvQkFDaEQsR0FBRyxDQUFDLElBQUksS0FBSyxjQUFjLENBQUMsc0JBQXNCLENBQUMsQ0FBQztZQUV4RCxJQUFJLFdBQVcsRUFBRSxDQUFDO2dCQUNoQiw4Q0FBOEM7Z0JBQzlDLE1BQU0sTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN4QyxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sK0RBQStEO2dCQUMvRCxvRUFBb0U7Z0JBQ3BFLE1BQU0sTUFBTSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDbkMsQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCx3REFBd0Q7SUFDeEQsTUFBTSxJQUFJLENBQUMsc0JBQXNCLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDakQsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpbmplY3QsIFBMQVRGT1JNX0lEIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyB0eXBlIENhbkFjdGl2YXRlRm4gfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuL2F1dGguc2VydmljZSc7XG5pbXBvcnQgeyBOQVVUSF9DTElFTlRfQ09ORklHIH0gZnJvbSAnLi90b2tlbnMnO1xuaW1wb3J0IHsgTkF1dGhDbGllbnRFcnJvciwgTkF1dGhFcnJvckNvZGUgfSBmcm9tICdAbmF1dGgtdG9vbGtpdC9jbGllbnQnO1xuXG4vKipcbiAqIFNvY2lhbCByZWRpcmVjdCBjYWxsYmFjayByb3V0ZSBndWFyZC5cbiAqXG4gKiBUaGlzIGd1YXJkIHN1cHBvcnRzIHRoZSByZWRpcmVjdC1maXJzdCBzb2NpYWwgZmxvdyB3aGVyZSB0aGUgYmFja2VuZCByZWRpcmVjdHNcbiAqIGJhY2sgdG8gdGhlIGZyb250ZW5kIHdpdGg6XG4gKiAtIGBhcHBTdGF0ZWAgKGFsd2F5cyBvcHRpb25hbClcbiAqIC0gYGV4Y2hhbmdlVG9rZW5gIChwcmVzZW50IGZvciBqc29uL2h5YnJpZCBmbG93cywgYW5kIGZvciBjb29raWUgZmxvd3MgdGhhdCByZXR1cm4gYSBjaGFsbGVuZ2UpXG4gKiAtIGBlcnJvcmAgLyBgZXJyb3JfZGVzY3JpcHRpb25gIChwcm92aWRlciBlcnJvcnMpXG4gKlxuICogQmVoYXZpb3I6XG4gKiAtIElmIGBleGNoYW5nZVRva2VuYCBleGlzdHM6IGV4Y2hhbmdlcyBpdCB2aWEgYmFja2VuZCAoU0RLIGhhbmRsZXMgbmF2aWdhdGlvbiBhdXRvbWF0aWNhbGx5KS5cbiAqIC0gSWYgbm8gYGV4Y2hhbmdlVG9rZW5gOiB0cmVhdCBhcyBjb29raWUtc3VjY2VzcyBwYXRoIChTREsgaGFuZGxlcyBuYXZpZ2F0aW9uIGF1dG9tYXRpY2FsbHkpLlxuICogLSBJZiBgZXJyb3JgIGV4aXN0czogcmVkaXJlY3RzIHRvIG9hdXRoRXJyb3Igcm91dGUuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IHNvY2lhbFJlZGlyZWN0Q2FsbGJhY2tHdWFyZCB9IGZyb20gJ0BuYXV0aC10b29sa2l0L2NsaWVudC9hbmd1bGFyJztcbiAqXG4gKiBleHBvcnQgY29uc3Qgcm91dGVzOiBSb3V0ZXMgPSBbXG4gKiAgIHsgcGF0aDogJ2F1dGgvY2FsbGJhY2snLCBjYW5BY3RpdmF0ZTogW3NvY2lhbFJlZGlyZWN0Q2FsbGJhY2tHdWFyZF0sIGNvbXBvbmVudDogQ2FsbGJhY2tDb21wb25lbnQgfSxcbiAqIF07XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IHNvY2lhbFJlZGlyZWN0Q2FsbGJhY2tHdWFyZDogQ2FuQWN0aXZhdGVGbiA9IGFzeW5jICgpOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgY29uc3QgYXV0aCA9IGluamVjdChBdXRoU2VydmljZSk7XG4gIGNvbnN0IHBsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpO1xuICBjb25zdCBpc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3NlcihwbGF0Zm9ybUlkKTtcblxuICBpZiAoIWlzQnJvd3Nlcikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGNvbnN0IHBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XG4gIGNvbnN0IGVycm9yID0gcGFyYW1zLmdldCgnZXJyb3InKTtcbiAgY29uc3QgZXhjaGFuZ2VUb2tlbiA9IHBhcmFtcy5nZXQoJ2V4Y2hhbmdlVG9rZW4nKTtcbiAgY29uc3Qgcm91dGVyID0gYXV0aC5nZXRDaGFsbGVuZ2VSb3V0ZXIoKTtcblxuICAvLyBQcm92aWRlciBlcnJvcjogcmVkaXJlY3QgdG8gb2F1dGhFcnJvclxuICBpZiAoZXJyb3IpIHtcbiAgICBhd2FpdCByb3V0ZXIubmF2aWdhdGVUb0Vycm9yKCdvYXV0aCcpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIE5vIGV4Y2hhbmdlVG9rZW46IGNvb2tpZSBzdWNjZXNzIHBhdGg7IGh5ZHJhdGUgdGhlbiBuYXZpZ2F0ZSB0byBzdWNjZXNzLlxuICAvL1xuICAvLyBOb3RlOiB3ZSBkbyBub3QgXCJhY3RpdmF0ZVwiIHRoZSBjYWxsYmFjayByb3V0ZSB0byBhdm9pZCBjb25zdW1lcnMgbmVlZGluZyB0byByZW5kZXIgYSBwYWdlLlxuICBpZiAoIWV4Y2hhbmdlVG9rZW4pIHtcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgLy8gQ29va2llcyBtb2RlOiBoeWRyYXRlIHVzZXIgc3RhdGUgYmVmb3JlIHJlZGlyZWN0aW5nXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgIC8vIFdIWTogSW4gY29va2llIGRlbGl2ZXJ5LCB0aGUgT0F1dGggY2FsbGJhY2sgY29tcGxldGVzIHZpYSBicm93c2VyIHJlZGlyZWN0cywgc28gdGhlIGZyb250ZW5kXG4gICAgLy8gZG9lcyBub3QgcmVjZWl2ZSBhIEpTT04gQXV0aFJlc3BvbnNlIHRvIHBvcHVsYXRlIHRoZSBTREsncyBjYWNoZWQgYGN1cnJlbnRVc2VyYC5cbiAgICAvL1xuICAgIC8vIFdpdGhvdXQgdGhpcywgc3luYyBndWFyZHMgKGBhdXRoR3VhcmRgKSBjYW4gaW1tZWRpYXRlbHkgcmVkaXJlY3QgdG8gL2xvZ2luIGJlY2F1c2VcbiAgICAvLyBgY3VycmVudFVzZXJgIGlzIHN0aWxsIG51bGwgZXZlbiB0aG91Z2ggY29va2llcyB3ZXJlIHNldCBzdWNjZXNzZnVsbHkuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGF1dGguZ2V0UHJvZmlsZSgpO1xuICAgICAgYXdhaXQgcm91dGVyLm5hdmlnYXRlVG9TdWNjZXNzKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBPbmx5IHRyZWF0IGF1dGggZmFpbHVyZXMgKDQwMS80MDMpIGFzIE9BdXRoIGVycm9yc1xuICAgICAgLy8gTmV0d29yayBlcnJvcnMgb3Igb3RoZXIgaXNzdWVzIG1pZ2h0IGJlIHRlbXBvcmFyeSAtIHN0aWxsIHRyeSBzdWNjZXNzIHJvdXRlXG4gICAgICBjb25zdCBpc0F1dGhFcnJvciA9XG4gICAgICAgIGVyciBpbnN0YW5jZW9mIE5BdXRoQ2xpZW50RXJyb3IgJiZcbiAgICAgICAgKGVyci5zdGF0dXNDb2RlID09PSA0MDEgfHxcbiAgICAgICAgICBlcnIuc3RhdHVzQ29kZSA9PT0gNDAzIHx8XG4gICAgICAgICAgZXJyLmNvZGUgPT09IE5BdXRoRXJyb3JDb2RlLkFVVEhfVE9LRU5fSU5WQUxJRCB8fFxuICAgICAgICAgIGVyci5jb2RlID09PSBOQXV0aEVycm9yQ29kZS5BVVRIX1NFU1NJT05fRVhQSVJFRCB8fFxuICAgICAgICAgIGVyci5jb2RlID09PSBOQXV0aEVycm9yQ29kZS5BVVRIX1NFU1NJT05fTk9UX0ZPVU5EKTtcblxuICAgICAgaWYgKGlzQXV0aEVycm9yKSB7XG4gICAgICAgIC8vIENvb2tpZXMgd2VyZW4ndCBzZXQgcHJvcGVybHkgLSBPQXV0aCBmYWlsZWRcbiAgICAgICAgYXdhaXQgcm91dGVyLm5hdmlnYXRlVG9FcnJvcignb2F1dGgnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEZvciBuZXR3b3JrIGVycm9ycyBvciBvdGhlciBpc3N1ZXMsIHByb2NlZWQgdG8gc3VjY2VzcyByb3V0ZVxuICAgICAgICAvLyBUaGUgYXV0aCBndWFyZCB3aWxsIGhhbmRsZSBhdXRoZW50aWNhdGlvbiBzdGF0ZSBvbiB0aGUgbmV4dCByb3V0ZVxuICAgICAgICBhd2FpdCByb3V0ZXIubmF2aWdhdGVUb1N1Y2Nlc3MoKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gRXhjaGFuZ2UgdG9rZW4gLSBTREsgaGFuZGxlcyBuYXZpZ2F0aW9uIGF1dG9tYXRpY2FsbHlcbiAgYXdhaXQgYXV0aC5leGNoYW5nZVNvY2lhbFJlZGlyZWN0KGV4Y2hhbmdlVG9rZW4pO1xuICByZXR1cm4gZmFsc2U7XG59O1xuIl19
@@ -1,13 +1,14 @@
1
1
  import { NAuthErrorCode, NAuthClientError, NAuthClient } from '@nauth-toolkit/client';
2
2
  export * from '@nauth-toolkit/client';
3
3
  import * as i0 from '@angular/core';
4
- import { InjectionToken, Injectable, Inject, inject, PLATFORM_ID } from '@angular/core';
4
+ import { InjectionToken, Injectable, Inject, inject, PLATFORM_ID, Optional } from '@angular/core';
5
5
  import { firstValueFrom, BehaviorSubject, Subject, catchError, throwError, from, switchMap, filter as filter$1, take } from 'rxjs';
6
6
  import { filter } from 'rxjs/operators';
7
7
  import * as i1 from '@angular/common/http';
8
8
  import { HttpErrorResponse, HttpClient } from '@angular/common/http';
9
9
  import { isPlatformBrowser } from '@angular/common';
10
10
  import { Router } from '@angular/router';
11
+ import { __decorate, __param } from 'tslib';
11
12
 
12
13
  /**
13
14
  * Injection token for providing NAuthClientConfig in Angular apps.
@@ -39,6 +40,37 @@ class AngularHttpAdapter {
39
40
  constructor(http) {
40
41
  this.http = http;
41
42
  }
43
+ /**
44
+ * Safely parse a JSON response body.
45
+ *
46
+ * Angular's fetch backend (`withFetch()`) will throw a raw `SyntaxError` if
47
+ * `responseType: 'json'` is used and the backend returns HTML (common for
48
+ * proxies, 502 pages, SSR fallbacks, or misrouted requests).
49
+ *
50
+ * To avoid crashing consumer apps, we always request as text and then parse
51
+ * JSON only when the response actually looks like JSON.
52
+ *
53
+ * @param bodyText - Raw response body as text
54
+ * @param contentType - Content-Type header value (if available)
55
+ * @returns Parsed JSON value (unknown)
56
+ * @throws {SyntaxError} When body is non-empty but not valid JSON
57
+ */
58
+ parseJsonBody(bodyText, contentType) {
59
+ const trimmed = bodyText.trim();
60
+ if (!trimmed)
61
+ return null;
62
+ // If it's clearly HTML, never attempt JSON.parse (some proxies mislabel Content-Type).
63
+ if (trimmed.startsWith('<')) {
64
+ return bodyText;
65
+ }
66
+ const looksLikeJson = trimmed.startsWith('{') || trimmed.startsWith('[');
67
+ const isJsonContentType = typeof contentType === 'string' && contentType.toLowerCase().includes('application/json');
68
+ if (!looksLikeJson && !isJsonContentType) {
69
+ // Return raw text when it doesn't look like JSON (e.g., HTML error pages).
70
+ return bodyText;
71
+ }
72
+ return JSON.parse(trimmed);
73
+ }
42
74
  /**
43
75
  * Execute HTTP request using Angular's HttpClient.
44
76
  *
@@ -48,29 +80,40 @@ class AngularHttpAdapter {
48
80
  */
49
81
  async request(config) {
50
82
  try {
51
- // Use Angular's HttpClient - goes through ALL interceptors
52
- const data = await firstValueFrom(this.http.request(config.method, config.url, {
83
+ // Use Angular's HttpClient - goes through ALL interceptors.
84
+ // IMPORTANT: Use responseType 'text' to avoid raw JSON.parse crashes when
85
+ // the backend returns HTML (seen in some proxy/SSR/misroute setups).
86
+ const res = await firstValueFrom(this.http.request(config.method, config.url, {
53
87
  body: config.body,
54
88
  headers: config.headers,
55
89
  withCredentials: config.credentials === 'include',
56
- observe: 'body', // Only return body data
90
+ observe: 'response',
91
+ responseType: 'text',
57
92
  }));
93
+ const contentType = res.headers?.get('content-type');
94
+ const parsed = this.parseJsonBody(res.body ?? '', contentType);
58
95
  return {
59
- data,
60
- status: 200, // HttpClient only returns data on success
61
- headers: {}, // Can extract from observe: 'response' if needed
96
+ data: parsed,
97
+ status: res.status,
98
+ headers: {}, // Reserved for future header passthrough if needed
62
99
  };
63
100
  }
64
101
  catch (error) {
65
102
  if (error instanceof HttpErrorResponse) {
66
- // Convert Angular's HttpErrorResponse to NAuthClientError
67
- const errorData = error.error || {};
68
- const code = typeof errorData['code'] === 'string' ? errorData.code : NAuthErrorCode.INTERNAL_ERROR;
103
+ // Convert Angular's HttpErrorResponse to NAuthClientError.
104
+ // When using responseType 'text', `error.error` is typically a string.
105
+ const contentType = error.headers?.get('content-type') ?? null;
106
+ const rawBody = typeof error.error === 'string' ? error.error : '';
107
+ const parsedError = this.parseJsonBody(rawBody, contentType);
108
+ const errorData = typeof parsedError === 'object' && parsedError !== null ? parsedError : {};
109
+ const code = typeof errorData['code'] === 'string' ? errorData['code'] : NAuthErrorCode.INTERNAL_ERROR;
69
110
  const message = typeof errorData['message'] === 'string'
70
- ? errorData.message
71
- : error.message || `Request failed with status ${error.status}`;
72
- const timestamp = typeof errorData['timestamp'] === 'string' ? errorData.timestamp : undefined;
73
- const details = errorData['details'];
111
+ ? errorData['message']
112
+ : typeof parsedError === 'string' && parsedError.trim()
113
+ ? parsedError
114
+ : error.message || `Request failed with status ${error.status}`;
115
+ const timestamp = typeof errorData['timestamp'] === 'string' ? errorData['timestamp'] : undefined;
116
+ const details = typeof errorData['details'] === 'object' ? errorData['details'] : undefined;
74
117
  throw new NAuthClientError(code, message, {
75
118
  statusCode: error.status,
76
119
  timestamp,
@@ -78,8 +121,12 @@ class AngularHttpAdapter {
78
121
  isNetworkError: error.status === 0, // Network error (no response from server)
79
122
  });
80
123
  }
81
- // Re-throw non-HTTP errors
82
- throw error;
124
+ // Re-throw non-HTTP errors as an SDK error so consumers don't see raw parser crashes.
125
+ const message = error instanceof Error ? error.message : 'Unknown error';
126
+ throw new NAuthClientError(NAuthErrorCode.INTERNAL_ERROR, message, {
127
+ statusCode: 0,
128
+ isNetworkError: true,
129
+ });
83
130
  }
84
131
  }
85
132
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
@@ -219,6 +266,21 @@ class AuthService {
219
266
  getCurrentChallenge() {
220
267
  return this.challengeSubject.value;
221
268
  }
269
+ /**
270
+ * Get challenge router for manual navigation control.
271
+ * Useful for guards that need to handle errors or build custom URLs.
272
+ *
273
+ * @returns ChallengeRouter instance
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * const router = this.auth.getChallengeRouter();
278
+ * await router.navigateToError('oauth');
279
+ * ```
280
+ */
281
+ getChallengeRouter() {
282
+ return this.client.getChallengeRouter();
283
+ }
222
284
  // ============================================================================
223
285
  // Core Auth Methods
224
286
  // ============================================================================
@@ -1014,20 +1076,24 @@ class AuthInterceptor {
1014
1076
  * Functional route guard for authentication (Angular 17+).
1015
1077
  *
1016
1078
  * Protects routes by checking if user is authenticated.
1017
- * Redirects to login page if not authenticated.
1079
+ * Redirects to configured session expired route (or login) if not authenticated.
1018
1080
  *
1019
- * @param redirectTo - Path to redirect to if not authenticated (default: '/login')
1081
+ * @param redirectTo - Optional path to redirect to if not authenticated. If not provided, uses `redirects.sessionExpired` from config (defaults to '/login')
1020
1082
  * @returns CanActivateFn guard function
1021
1083
  *
1022
1084
  * @example
1023
1085
  * ```typescript
1024
- * // In route configuration
1086
+ * // In route configuration - uses config.redirects.sessionExpired
1025
1087
  * const routes: Routes = [
1026
1088
  * {
1027
1089
  * path: 'home',
1028
1090
  * component: HomeComponent,
1029
1091
  * canActivate: [authGuard()]
1030
- * },
1092
+ * }
1093
+ * ];
1094
+ *
1095
+ * // Override with custom route
1096
+ * const routes: Routes = [
1031
1097
  * {
1032
1098
  * path: 'admin',
1033
1099
  * component: AdminComponent,
@@ -1036,14 +1102,17 @@ class AuthInterceptor {
1036
1102
  * ];
1037
1103
  * ```
1038
1104
  */
1039
- function authGuard(redirectTo = '/login') {
1105
+ function authGuard(redirectTo) {
1040
1106
  return () => {
1041
1107
  const auth = inject(AuthService);
1042
1108
  const router = inject(Router);
1109
+ const config = inject(NAUTH_CLIENT_CONFIG, { optional: true });
1043
1110
  if (auth.isAuthenticated()) {
1044
1111
  return true;
1045
1112
  }
1046
- return router.createUrlTree([redirectTo]);
1113
+ // Use provided redirectTo, or config.redirects.sessionExpired, or default to '/login'
1114
+ const redirectPath = redirectTo ?? config?.redirects?.sessionExpired ?? '/login';
1115
+ return router.createUrlTree([redirectPath]);
1047
1116
  };
1048
1117
  }
1049
1118
  /**
@@ -1066,29 +1135,38 @@ function authGuard(redirectTo = '/login') {
1066
1135
  * })
1067
1136
  * ```
1068
1137
  */
1069
- class AuthGuard {
1138
+ let AuthGuard = class AuthGuard {
1070
1139
  auth;
1071
1140
  router;
1141
+ config;
1072
1142
  /**
1073
1143
  * @param auth - Authentication service
1074
1144
  * @param router - Angular router
1145
+ * @param config - Optional client configuration (injected automatically)
1075
1146
  */
1076
- constructor(auth, router) {
1147
+ constructor(auth, router, config) {
1077
1148
  this.auth = auth;
1078
1149
  this.router = router;
1150
+ this.config = config;
1079
1151
  }
1080
1152
  /**
1081
1153
  * Check if route can be activated.
1082
1154
  *
1083
- * @returns True if authenticated, otherwise redirects to login
1155
+ * @returns True if authenticated, otherwise redirects to configured session expired route (or '/login')
1084
1156
  */
1085
1157
  canActivate() {
1086
1158
  if (this.auth.isAuthenticated()) {
1087
1159
  return true;
1088
1160
  }
1089
- return this.router.createUrlTree(['/login']);
1161
+ // Use config.redirects.sessionExpired or default to '/login'
1162
+ const redirectPath = this.config?.redirects?.sessionExpired ?? '/login';
1163
+ return this.router.createUrlTree([redirectPath]);
1090
1164
  }
1091
- }
1165
+ };
1166
+ AuthGuard = __decorate([
1167
+ __param(2, Optional()),
1168
+ __param(2, Inject(NAUTH_CLIENT_CONFIG))
1169
+ ], AuthGuard);
1092
1170
 
1093
1171
  /**
1094
1172
  * Social redirect callback route guard.
@@ -1100,8 +1178,8 @@ class AuthGuard {
1100
1178
  * - `error` / `error_description` (provider errors)
1101
1179
  *
1102
1180
  * Behavior:
1103
- * - If `exchangeToken` exists: exchanges it via backend and redirects to success or challenge routes.
1104
- * - If no `exchangeToken`: treat as cookie-success path and redirect to success route.
1181
+ * - If `exchangeToken` exists: exchanges it via backend (SDK handles navigation automatically).
1182
+ * - If no `exchangeToken`: treat as cookie-success path (SDK handles navigation automatically).
1105
1183
  * - If `error` exists: redirects to oauthError route.
1106
1184
  *
1107
1185
  * @example
@@ -1115,7 +1193,6 @@ class AuthGuard {
1115
1193
  */
1116
1194
  const socialRedirectCallbackGuard = async () => {
1117
1195
  const auth = inject(AuthService);
1118
- const config = inject(NAUTH_CLIENT_CONFIG);
1119
1196
  const platformId = inject(PLATFORM_ID);
1120
1197
  const isBrowser = isPlatformBrowser(platformId);
1121
1198
  if (!isBrowser) {
@@ -1124,13 +1201,13 @@ const socialRedirectCallbackGuard = async () => {
1124
1201
  const params = new URLSearchParams(window.location.search);
1125
1202
  const error = params.get('error');
1126
1203
  const exchangeToken = params.get('exchangeToken');
1204
+ const router = auth.getChallengeRouter();
1127
1205
  // Provider error: redirect to oauthError
1128
1206
  if (error) {
1129
- const errorUrl = config.redirects?.oauthError || '/login';
1130
- window.location.replace(errorUrl);
1207
+ await router.navigateToError('oauth');
1131
1208
  return false;
1132
1209
  }
1133
- // No exchangeToken: cookie success path; redirect to success.
1210
+ // No exchangeToken: cookie success path; hydrate then navigate to success.
1134
1211
  //
1135
1212
  // Note: we do not "activate" the callback route to avoid consumers needing to render a page.
1136
1213
  if (!exchangeToken) {
@@ -1144,26 +1221,31 @@ const socialRedirectCallbackGuard = async () => {
1144
1221
  // `currentUser` is still null even though cookies were set successfully.
1145
1222
  try {
1146
1223
  await auth.getProfile();
1224
+ await router.navigateToSuccess();
1147
1225
  }
1148
- catch {
1149
- const errorUrl = config.redirects?.oauthError || '/login';
1150
- window.location.replace(errorUrl);
1151
- return false;
1226
+ catch (err) {
1227
+ // Only treat auth failures (401/403) as OAuth errors
1228
+ // Network errors or other issues might be temporary - still try success route
1229
+ const isAuthError = err instanceof NAuthClientError &&
1230
+ (err.statusCode === 401 ||
1231
+ err.statusCode === 403 ||
1232
+ err.code === NAuthErrorCode.AUTH_TOKEN_INVALID ||
1233
+ err.code === NAuthErrorCode.AUTH_SESSION_EXPIRED ||
1234
+ err.code === NAuthErrorCode.AUTH_SESSION_NOT_FOUND);
1235
+ if (isAuthError) {
1236
+ // Cookies weren't set properly - OAuth failed
1237
+ await router.navigateToError('oauth');
1238
+ }
1239
+ else {
1240
+ // For network errors or other issues, proceed to success route
1241
+ // The auth guard will handle authentication state on the next route
1242
+ await router.navigateToSuccess();
1243
+ }
1152
1244
  }
1153
- const successUrl = config.redirects?.success || '/';
1154
- window.location.replace(successUrl);
1155
- return false;
1156
- }
1157
- // Exchange token and route accordingly
1158
- const response = await auth.exchangeSocialRedirect(exchangeToken);
1159
- if (response.challengeName) {
1160
- const challengeBase = config.redirects?.challengeBase || '/auth/challenge';
1161
- const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, '-');
1162
- window.location.replace(`${challengeBase}/${challengeRoute}`);
1163
1245
  return false;
1164
1246
  }
1165
- const successUrl = config.redirects?.success || '/';
1166
- window.location.replace(successUrl);
1247
+ // Exchange token - SDK handles navigation automatically
1248
+ await auth.exchangeSocialRedirect(exchangeToken);
1167
1249
  return false;
1168
1250
  };
1169
1251