@nauth-toolkit/client-angular 0.1.56 → 0.1.58
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/esm2022/lib/auth.guard.mjs +83 -0
- package/esm2022/lib/auth.interceptor.mjs +158 -0
- package/esm2022/lib/social-redirect-callback.guard.mjs +81 -0
- package/esm2022/nauth-toolkit-client-angular.mjs +5 -0
- package/esm2022/ngmodule/auth.interceptor.class.mjs +109 -0
- package/esm2022/ngmodule/auth.service.mjs +777 -0
- package/esm2022/ngmodule/http-adapter.mjs +127 -0
- package/esm2022/ngmodule/nauth.module.mjs +65 -0
- package/esm2022/ngmodule/tokens.mjs +6 -0
- package/esm2022/public-api.mjs +19 -0
- package/esm2022/src/standalone/nauth-toolkit-client-angular-src-standalone.mjs +5 -0
- package/esm2022/src/standalone/public-api.mjs +12 -0
- package/esm2022/standalone/auth.guard.mjs +83 -0
- package/esm2022/standalone/auth.interceptor.mjs +158 -0
- package/esm2022/standalone/auth.service.mjs +777 -0
- package/esm2022/standalone/http-adapter.mjs +127 -0
- package/esm2022/standalone/nauth-toolkit-client-angular-standalone.mjs +5 -0
- package/esm2022/standalone/public-api.mjs +16 -0
- package/esm2022/standalone/social-redirect-callback.guard.mjs +81 -0
- package/esm2022/standalone/tokens.mjs +6 -0
- package/fesm2022/nauth-toolkit-client-angular-src-standalone.mjs +17 -0
- package/fesm2022/nauth-toolkit-client-angular-src-standalone.mjs.map +1 -0
- package/fesm2022/nauth-toolkit-client-angular-standalone.mjs +1229 -0
- package/fesm2022/nauth-toolkit-client-angular-standalone.mjs.map +1 -0
- package/fesm2022/nauth-toolkit-client-angular.mjs +1390 -0
- package/fesm2022/nauth-toolkit-client-angular.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/{src/lib/auth.guard.ts → lib/auth.guard.d.ts} +15 -37
- package/lib/auth.interceptor.d.ts +15 -0
- package/lib/social-redirect-callback.guard.d.ts +25 -0
- package/ngmodule/auth.interceptor.class.d.ts +34 -0
- package/ngmodule/auth.service.d.ts +580 -0
- package/ngmodule/http-adapter.d.ts +53 -0
- package/ngmodule/nauth.module.d.ts +31 -0
- package/{src/ngmodule/tokens.ts → ngmodule/tokens.d.ts} +1 -2
- package/package.json +30 -20
- package/{src/public-api.ts → public-api.d.ts} +0 -6
- package/src/standalone/index.d.ts +5 -0
- package/src/standalone/{public-api.ts → public-api.d.ts} +0 -2
- package/standalone/{auth.guard.ts → auth.guard.d.ts} +15 -37
- package/standalone/auth.interceptor.d.ts +15 -0
- package/standalone/auth.service.d.ts +580 -0
- package/standalone/http-adapter.d.ts +53 -0
- package/standalone/index.d.ts +5 -0
- package/standalone/{public-api.ts → public-api.d.ts} +1 -6
- package/standalone/social-redirect-callback.guard.d.ts +25 -0
- package/standalone/{tokens.ts → tokens.d.ts} +1 -2
- package/ng-package.json +0 -12
- package/src/lib/auth.interceptor.ts +0 -194
- package/src/lib/social-redirect-callback.guard.ts +0 -87
- package/src/ngmodule/auth.interceptor.class.ts +0 -124
- package/src/ngmodule/auth.service.ts +0 -865
- package/src/ngmodule/http-adapter.ts +0 -79
- package/src/ngmodule/nauth.module.ts +0 -59
- package/src/package.json +0 -11
- package/src/standalone/ng-package.json +0 -7
- package/src/standalone/package.json +0 -8
- package/standalone/auth.interceptor.ts +0 -194
- package/standalone/auth.service.ts +0 -865
- package/standalone/http-adapter.ts +0 -79
- package/standalone/ng-package.json +0 -7
- package/standalone/package.json +0 -8
- package/standalone/social-redirect-callback.guard.ts +0 -87
- package/tsconfig.json +0 -10
- package/tsconfig.lib.json +0 -28
- package/tsconfig.lib.prod.json +0 -10
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
3
|
+
import { firstValueFrom } from 'rxjs';
|
|
4
|
+
import { NAuthClientError, NAuthErrorCode } from '@nauth-toolkit/client';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@angular/common/http";
|
|
7
|
+
/**
|
|
8
|
+
* HTTP adapter for Angular using HttpClient.
|
|
9
|
+
*
|
|
10
|
+
* This adapter:
|
|
11
|
+
* - Uses Angular's HttpClient for all requests
|
|
12
|
+
* - Works with Angular's HTTP interceptors (including authInterceptor)
|
|
13
|
+
* - Auto-provided via Angular DI (providedIn: 'root')
|
|
14
|
+
* - Converts HttpClient responses to HttpResponse format
|
|
15
|
+
* - Converts HttpErrorResponse to NAuthClientError
|
|
16
|
+
*
|
|
17
|
+
* Users don't need to configure this manually - it's automatically
|
|
18
|
+
* injected when using AuthService in Angular apps.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Automatic usage (no manual setup needed)
|
|
23
|
+
* // AuthService automatically injects AngularHttpAdapter
|
|
24
|
+
* constructor(private auth: AuthService) {}
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class AngularHttpAdapter {
|
|
28
|
+
http;
|
|
29
|
+
constructor(http) {
|
|
30
|
+
this.http = http;
|
|
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
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Execute HTTP request using Angular's HttpClient.
|
|
65
|
+
*
|
|
66
|
+
* @param config - Request configuration
|
|
67
|
+
* @returns Response with parsed data
|
|
68
|
+
* @throws NAuthClientError if request fails
|
|
69
|
+
*/
|
|
70
|
+
async request(config) {
|
|
71
|
+
try {
|
|
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, {
|
|
76
|
+
body: config.body,
|
|
77
|
+
headers: config.headers,
|
|
78
|
+
withCredentials: config.credentials === 'include',
|
|
79
|
+
observe: 'response',
|
|
80
|
+
responseType: 'text',
|
|
81
|
+
}));
|
|
82
|
+
const contentType = res.headers?.get('content-type');
|
|
83
|
+
const parsed = this.parseJsonBody(res.body ?? '', contentType);
|
|
84
|
+
return {
|
|
85
|
+
data: parsed,
|
|
86
|
+
status: res.status,
|
|
87
|
+
headers: {}, // Reserved for future header passthrough if needed
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error instanceof HttpErrorResponse) {
|
|
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;
|
|
99
|
+
const message = typeof errorData['message'] === 'string'
|
|
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;
|
|
106
|
+
throw new NAuthClientError(code, message, {
|
|
107
|
+
statusCode: error.status,
|
|
108
|
+
timestamp,
|
|
109
|
+
details,
|
|
110
|
+
isNetworkError: error.status === 0, // Network error (no response from server)
|
|
111
|
+
});
|
|
112
|
+
}
|
|
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
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
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 });
|
|
122
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter });
|
|
123
|
+
}
|
|
124
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter, decorators: [{
|
|
125
|
+
type: Injectable
|
|
126
|
+
}], ctorParameters: () => [{ type: i1.HttpClient }] });
|
|
127
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1hZGFwdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL25nbW9kdWxlL2h0dHAtYWRhcHRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBYyxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEMsT0FBTyxFQUEwQyxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7O0FBRWpIOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBRUgsTUFBTSxPQUFPLGtCQUFrQjtJQUNBO0lBQTdCLFlBQTZCLElBQWdCO1FBQWhCLFNBQUksR0FBSixJQUFJLENBQVk7SUFBRyxDQUFDO0lBRWpEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ0ssYUFBYSxDQUFDLFFBQWdCLEVBQUUsV0FBMEI7UUFDaEUsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFMUIsdUZBQXVGO1FBQ3ZGLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVCLE9BQU8sUUFBUSxDQUFDO1FBQ2xCLENBQUM7UUFFRCxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDekUsTUFBTSxpQkFBaUIsR0FBRyxPQUFPLFdBQVcsS0FBSyxRQUFRLElBQUksV0FBVyxDQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBRXBILElBQUksQ0FBQyxhQUFhLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ3pDLDJFQUEyRTtZQUMzRSxPQUFPLFFBQVEsQ0FBQztRQUNsQixDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBWSxDQUFDO0lBQ3hDLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUFJLE1BQW1CO1FBQ2xDLElBQUksQ0FBQztZQUNILDREQUE0RDtZQUM1RCwwRUFBMEU7WUFDMUUscUVBQXFFO1lBQ3JFLE1BQU0sR0FBRyxHQUFHLE1BQU0sY0FBYyxDQUM5QixJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxHQUFHLEVBQUU7Z0JBQzNDLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtnQkFDakIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPO2dCQUN2QixlQUFlLEVBQUUsTUFBTSxDQUFDLFdBQVcsS0FBSyxTQUFTO2dCQUNqRCxPQUFPLEVBQUUsVUFBVTtnQkFDbkIsWUFBWSxFQUFFLE1BQU07YUFDckIsQ0FBQyxDQUNILENBQUM7WUFFRixNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUNyRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBRS9ELE9BQU87Z0JBQ0wsSUFBSSxFQUFFLE1BQVc7Z0JBQ2pCLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTTtnQkFDbEIsT0FBTyxFQUFFLEVBQUUsRUFBRSxtREFBbUQ7YUFDakUsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxLQUFLLFlBQVksaUJBQWlCLEVBQUUsQ0FBQztnQkFDdkMsMkRBQTJEO2dCQUMzRCx1RUFBdUU7Z0JBQ3ZFLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLGNBQWMsQ0FBQyxJQUFJLElBQUksQ0FBQztnQkFDL0QsTUFBTSxPQUFPLEdBQUcsT0FBTyxLQUFLLENBQUMsS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUNuRSxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQztnQkFFN0QsTUFBTSxTQUFTLEdBQ2IsT0FBTyxXQUFXLEtBQUssUUFBUSxJQUFJLFdBQVcsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFFLFdBQXVDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDMUcsTUFBTSxJQUFJLEdBQ1IsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBRSxTQUFTLENBQUMsTUFBTSxDQUFvQixDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsY0FBYyxDQUFDO2dCQUNoSCxNQUFNLE9BQU8sR0FDWCxPQUFPLFNBQVMsQ0FBQyxTQUFTLENBQUMsS0FBSyxRQUFRO29CQUN0QyxDQUFDLENBQUUsU0FBUyxDQUFDLFNBQVMsQ0FBWTtvQkFDbEMsQ0FBQyxDQUFDLE9BQU8sV0FBVyxLQUFLLFFBQVEsSUFBSSxXQUFXLENBQUMsSUFBSSxFQUFFO3dCQUNyRCxDQUFDLENBQUMsV0FBVzt3QkFDYixDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sSUFBSSw4QkFBOEIsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUN0RSxNQUFNLFNBQVMsR0FBRyxPQUFPLFNBQVMsQ0FBQyxXQUFXLENBQUMsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFFLFNBQVMsQ0FBQyxXQUFXLENBQVksQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO2dCQUM5RyxNQUFNLE9BQU8sR0FDWCxPQUFPLFNBQVMsQ0FBQyxTQUFTLENBQUMsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFFLFNBQVMsQ0FBQyxTQUFTLENBQTZCLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztnQkFFM0csTUFBTSxJQUFJLGdCQUFnQixDQUFDLElBQUksRUFBRSxPQUFPLEVBQUU7b0JBQ3hDLFVBQVUsRUFBRSxLQUFLLENBQUMsTUFBTTtvQkFDeEIsU0FBUztvQkFDVCxPQUFPO29CQUNQLGNBQWMsRUFBRSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSwwQ0FBMEM7aUJBQy9FLENBQUMsQ0FBQztZQUNMLENBQUM7WUFFRCxzRkFBc0Y7WUFDdEYsTUFBTSxPQUFPLEdBQUcsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDO1lBQ3pFLE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxjQUFjLENBQUMsY0FBYyxFQUFFLE9BQU8sRUFBRTtnQkFDakUsVUFBVSxFQUFFLENBQUM7Z0JBQ2IsY0FBYyxFQUFFLElBQUk7YUFDckIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7d0dBekdVLGtCQUFrQjs0R0FBbEIsa0JBQWtCOzs0RkFBbEIsa0JBQWtCO2tCQUQ5QixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSHR0cENsaWVudCwgSHR0cEVycm9yUmVzcG9uc2UgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBmaXJzdFZhbHVlRnJvbSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgSHR0cEFkYXB0ZXIsIEh0dHBSZXF1ZXN0LCBIdHRwUmVzcG9uc2UsIE5BdXRoQ2xpZW50RXJyb3IsIE5BdXRoRXJyb3JDb2RlIH0gZnJvbSAnQG5hdXRoLXRvb2xraXQvY2xpZW50JztcblxuLyoqXG4gKiBIVFRQIGFkYXB0ZXIgZm9yIEFuZ3VsYXIgdXNpbmcgSHR0cENsaWVudC5cbiAqXG4gKiBUaGlzIGFkYXB0ZXI6XG4gKiAtIFVzZXMgQW5ndWxhcidzIEh0dHBDbGllbnQgZm9yIGFsbCByZXF1ZXN0c1xuICogLSBXb3JrcyB3aXRoIEFuZ3VsYXIncyBIVFRQIGludGVyY2VwdG9ycyAoaW5jbHVkaW5nIGF1dGhJbnRlcmNlcHRvcilcbiAqIC0gQXV0by1wcm92aWRlZCB2aWEgQW5ndWxhciBESSAocHJvdmlkZWRJbjogJ3Jvb3QnKVxuICogLSBDb252ZXJ0cyBIdHRwQ2xpZW50IHJlc3BvbnNlcyB0byBIdHRwUmVzcG9uc2UgZm9ybWF0XG4gKiAtIENvbnZlcnRzIEh0dHBFcnJvclJlc3BvbnNlIHRvIE5BdXRoQ2xpZW50RXJyb3JcbiAqXG4gKiBVc2VycyBkb24ndCBuZWVkIHRvIGNvbmZpZ3VyZSB0aGlzIG1hbnVhbGx5IC0gaXQncyBhdXRvbWF0aWNhbGx5XG4gKiBpbmplY3RlZCB3aGVuIHVzaW5nIEF1dGhTZXJ2aWNlIGluIEFuZ3VsYXIgYXBwcy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gQXV0b21hdGljIHVzYWdlIChubyBtYW51YWwgc2V0dXAgbmVlZGVkKVxuICogLy8gQXV0aFNlcnZpY2UgYXV0b21hdGljYWxseSBpbmplY3RzIEFuZ3VsYXJIdHRwQWRhcHRlclxuICogY29uc3RydWN0b3IocHJpdmF0ZSBhdXRoOiBBdXRoU2VydmljZSkge31cbiAqIGBgYFxuICovXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgQW5ndWxhckh0dHBBZGFwdGVyIGltcGxlbWVudHMgSHR0cEFkYXB0ZXIge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGh0dHA6IEh0dHBDbGllbnQpIHt9XG5cbiAgLyoqXG4gICAqIFNhZmVseSBwYXJzZSBhIEpTT04gcmVzcG9uc2UgYm9keS5cbiAgICpcbiAgICogQW5ndWxhcidzIGZldGNoIGJhY2tlbmQgKGB3aXRoRmV0Y2goKWApIHdpbGwgdGhyb3cgYSByYXcgYFN5bnRheEVycm9yYCBpZlxuICAgKiBgcmVzcG9uc2VUeXBlOiAnanNvbidgIGlzIHVzZWQgYW5kIHRoZSBiYWNrZW5kIHJldHVybnMgSFRNTCAoY29tbW9uIGZvclxuICAgKiBwcm94aWVzLCA1MDIgcGFnZXMsIFNTUiBmYWxsYmFja3MsIG9yIG1pc3JvdXRlZCByZXF1ZXN0cykuXG4gICAqXG4gICAqIFRvIGF2b2lkIGNyYXNoaW5nIGNvbnN1bWVyIGFwcHMsIHdlIGFsd2F5cyByZXF1ZXN0IGFzIHRleHQgYW5kIHRoZW4gcGFyc2VcbiAgICogSlNPTiBvbmx5IHdoZW4gdGhlIHJlc3BvbnNlIGFjdHVhbGx5IGxvb2tzIGxpa2UgSlNPTi5cbiAgICpcbiAgICogQHBhcmFtIGJvZHlUZXh0IC0gUmF3IHJlc3BvbnNlIGJvZHkgYXMgdGV4dFxuICAgKiBAcGFyYW0gY29udGVudFR5cGUgLSBDb250ZW50LVR5cGUgaGVhZGVyIHZhbHVlIChpZiBhdmFpbGFibGUpXG4gICAqIEByZXR1cm5zIFBhcnNlZCBKU09OIHZhbHVlICh1bmtub3duKVxuICAgKiBAdGhyb3dzIHtTeW50YXhFcnJvcn0gV2hlbiBib2R5IGlzIG5vbi1lbXB0eSBidXQgbm90IHZhbGlkIEpTT05cbiAgICovXG4gIHByaXZhdGUgcGFyc2VKc29uQm9keShib2R5VGV4dDogc3RyaW5nLCBjb250ZW50VHlwZTogc3RyaW5nIHwgbnVsbCk6IHVua25vd24ge1xuICAgIGNvbnN0IHRyaW1tZWQgPSBib2R5VGV4dC50cmltKCk7XG4gICAgaWYgKCF0cmltbWVkKSByZXR1cm4gbnVsbDtcblxuICAgIC8vIElmIGl0J3MgY2xlYXJseSBIVE1MLCBuZXZlciBhdHRlbXB0IEpTT04ucGFyc2UgKHNvbWUgcHJveGllcyBtaXNsYWJlbCBDb250ZW50LVR5cGUpLlxuICAgIGlmICh0cmltbWVkLnN0YXJ0c1dpdGgoJzwnKSkge1xuICAgICAgcmV0dXJuIGJvZHlUZXh0O1xuICAgIH1cblxuICAgIGNvbnN0IGxvb2tzTGlrZUpzb24gPSB0cmltbWVkLnN0YXJ0c1dpdGgoJ3snKSB8fCB0cmltbWVkLnN0YXJ0c1dpdGgoJ1snKTtcbiAgICBjb25zdCBpc0pzb25Db250ZW50VHlwZSA9IHR5cGVvZiBjb250ZW50VHlwZSA9PT0gJ3N0cmluZycgJiYgY29udGVudFR5cGUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpO1xuXG4gICAgaWYgKCFsb29rc0xpa2VKc29uICYmICFpc0pzb25Db250ZW50VHlwZSkge1xuICAgICAgLy8gUmV0dXJuIHJhdyB0ZXh0IHdoZW4gaXQgZG9lc24ndCBsb29rIGxpa2UgSlNPTiAoZS5nLiwgSFRNTCBlcnJvciBwYWdlcykuXG4gICAgICByZXR1cm4gYm9keVRleHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIEpTT04ucGFyc2UodHJpbW1lZCkgYXMgdW5rbm93bjtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlIEhUVFAgcmVxdWVzdCB1c2luZyBBbmd1bGFyJ3MgSHR0cENsaWVudC5cbiAgICpcbiAgICogQHBhcmFtIGNvbmZpZyAtIFJlcXVlc3QgY29uZmlndXJhdGlvblxuICAgKiBAcmV0dXJucyBSZXNwb25zZSB3aXRoIHBhcnNlZCBkYXRhXG4gICAqIEB0aHJvd3MgTkF1dGhDbGllbnRFcnJvciBpZiByZXF1ZXN0IGZhaWxzXG4gICAqL1xuICBhc3luYyByZXF1ZXN0PFQ+KGNvbmZpZzogSHR0cFJlcXVlc3QpOiBQcm9taXNlPEh0dHBSZXNwb25zZTxUPj4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBVc2UgQW5ndWxhcidzIEh0dHBDbGllbnQgLSBnb2VzIHRocm91Z2ggQUxMIGludGVyY2VwdG9ycy5cbiAgICAgIC8vIElNUE9SVEFOVDogVXNlIHJlc3BvbnNlVHlwZSAndGV4dCcgdG8gYXZvaWQgcmF3IEpTT04ucGFyc2UgY3Jhc2hlcyB3aGVuXG4gICAgICAvLyB0aGUgYmFja2VuZCByZXR1cm5zIEhUTUwgKHNlZW4gaW4gc29tZSBwcm94eS9TU1IvbWlzcm91dGUgc2V0dXBzKS5cbiAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IGZpcnN0VmFsdWVGcm9tKFxuICAgICAgICB0aGlzLmh0dHAucmVxdWVzdChjb25maWcubWV0aG9kLCBjb25maWcudXJsLCB7XG4gICAgICAgICAgYm9keTogY29uZmlnLmJvZHksXG4gICAgICAgICAgaGVhZGVyczogY29uZmlnLmhlYWRlcnMsXG4gICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiBjb25maWcuY3JlZGVudGlhbHMgPT09ICdpbmNsdWRlJyxcbiAgICAgICAgICBvYnNlcnZlOiAncmVzcG9uc2UnLFxuICAgICAgICAgIHJlc3BvbnNlVHlwZTogJ3RleHQnLFxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVzLmhlYWRlcnM/LmdldCgnY29udGVudC10eXBlJyk7XG4gICAgICBjb25zdCBwYXJzZWQgPSB0aGlzLnBhcnNlSnNvbkJvZHkocmVzLmJvZHkgPz8gJycsIGNvbnRlbnRUeXBlKTtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZGF0YTogcGFyc2VkIGFzIFQsXG4gICAgICAgIHN0YXR1czogcmVzLnN0YXR1cyxcbiAgICAgICAgaGVhZGVyczoge30sIC8vIFJlc2VydmVkIGZvciBmdXR1cmUgaGVhZGVyIHBhc3N0aHJvdWdoIGlmIG5lZWRlZFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgSHR0cEVycm9yUmVzcG9uc2UpIHtcbiAgICAgICAgLy8gQ29udmVydCBBbmd1bGFyJ3MgSHR0cEVycm9yUmVzcG9uc2UgdG8gTkF1dGhDbGllbnRFcnJvci5cbiAgICAgICAgLy8gV2hlbiB1c2luZyByZXNwb25zZVR5cGUgJ3RleHQnLCBgZXJyb3IuZXJyb3JgIGlzIHR5cGljYWxseSBhIHN0cmluZy5cbiAgICAgICAgY29uc3QgY29udGVudFR5cGUgPSBlcnJvci5oZWFkZXJzPy5nZXQoJ2NvbnRlbnQtdHlwZScpID8/IG51bGw7XG4gICAgICAgIGNvbnN0IHJhd0JvZHkgPSB0eXBlb2YgZXJyb3IuZXJyb3IgPT09ICdzdHJpbmcnID8gZXJyb3IuZXJyb3IgOiAnJztcbiAgICAgICAgY29uc3QgcGFyc2VkRXJyb3IgPSB0aGlzLnBhcnNlSnNvbkJvZHkocmF3Qm9keSwgY29udGVudFR5cGUpO1xuXG4gICAgICAgIGNvbnN0IGVycm9yRGF0YSA9XG4gICAgICAgICAgdHlwZW9mIHBhcnNlZEVycm9yID09PSAnb2JqZWN0JyAmJiBwYXJzZWRFcnJvciAhPT0gbnVsbCA/IChwYXJzZWRFcnJvciBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikgOiB7fTtcbiAgICAgICAgY29uc3QgY29kZSA9XG4gICAgICAgICAgdHlwZW9mIGVycm9yRGF0YVsnY29kZSddID09PSAnc3RyaW5nJyA/IChlcnJvckRhdGFbJ2NvZGUnXSBhcyBOQXV0aEVycm9yQ29kZSkgOiBOQXV0aEVycm9yQ29kZS5JTlRFUk5BTF9FUlJPUjtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9XG4gICAgICAgICAgdHlwZW9mIGVycm9yRGF0YVsnbWVzc2FnZSddID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgPyAoZXJyb3JEYXRhWydtZXNzYWdlJ10gYXMgc3RyaW5nKVxuICAgICAgICAgICAgOiB0eXBlb2YgcGFyc2VkRXJyb3IgPT09ICdzdHJpbmcnICYmIHBhcnNlZEVycm9yLnRyaW0oKVxuICAgICAgICAgICAgICA/IHBhcnNlZEVycm9yXG4gICAgICAgICAgICAgIDogZXJyb3IubWVzc2FnZSB8fCBgUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgJHtlcnJvci5zdGF0dXN9YDtcbiAgICAgICAgY29uc3QgdGltZXN0YW1wID0gdHlwZW9mIGVycm9yRGF0YVsndGltZXN0YW1wJ10gPT09ICdzdHJpbmcnID8gKGVycm9yRGF0YVsndGltZXN0YW1wJ10gYXMgc3RyaW5nKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgZGV0YWlscyA9XG4gICAgICAgICAgdHlwZW9mIGVycm9yRGF0YVsnZGV0YWlscyddID09PSAnb2JqZWN0JyA/IChlcnJvckRhdGFbJ2RldGFpbHMnXSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikgOiB1bmRlZmluZWQ7XG5cbiAgICAgICAgdGhyb3cgbmV3IE5BdXRoQ2xpZW50RXJyb3IoY29kZSwgbWVzc2FnZSwge1xuICAgICAgICAgIHN0YXR1c0NvZGU6IGVycm9yLnN0YXR1cyxcbiAgICAgICAgICB0aW1lc3RhbXAsXG4gICAgICAgICAgZGV0YWlscyxcbiAgICAgICAgICBpc05ldHdvcmtFcnJvcjogZXJyb3Iuc3RhdHVzID09PSAwLCAvLyBOZXR3b3JrIGVycm9yIChubyByZXNwb25zZSBmcm9tIHNlcnZlcilcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIFJlLXRocm93IG5vbi1IVFRQIGVycm9ycyBhcyBhbiBTREsgZXJyb3Igc28gY29uc3VtZXJzIGRvbid0IHNlZSByYXcgcGFyc2VyIGNyYXNoZXMuXG4gICAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcic7XG4gICAgICB0aHJvdyBuZXcgTkF1dGhDbGllbnRFcnJvcihOQXV0aEVycm9yQ29kZS5JTlRFUk5BTF9FUlJPUiwgbWVzc2FnZSwge1xuICAgICAgICBzdGF0dXNDb2RlOiAwLFxuICAgICAgICBpc05ldHdvcmtFcnJvcjogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
3
|
+
import { NAUTH_CLIENT_CONFIG } from './tokens';
|
|
4
|
+
import { AuthService } from './auth.service';
|
|
5
|
+
import { AngularHttpAdapter } from './http-adapter';
|
|
6
|
+
import { AuthInterceptorClass } from './auth.interceptor.class';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
/**
|
|
9
|
+
* NgModule for nauth-toolkit Angular integration.
|
|
10
|
+
*
|
|
11
|
+
* Use this for NgModule-based apps (Angular 17+ with NgModule or legacy apps).
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // app.module.ts
|
|
16
|
+
* import { NAuthModule } from '@nauth-toolkit/client-angular';
|
|
17
|
+
*
|
|
18
|
+
* @NgModule({
|
|
19
|
+
* imports: [
|
|
20
|
+
* NAuthModule.forRoot({
|
|
21
|
+
* baseUrl: 'http://localhost:3000/auth',
|
|
22
|
+
* tokenDelivery: 'cookies',
|
|
23
|
+
* }),
|
|
24
|
+
* ],
|
|
25
|
+
* })
|
|
26
|
+
* export class AppModule {}
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class NAuthModule {
|
|
30
|
+
static forRoot(config) {
|
|
31
|
+
return {
|
|
32
|
+
ngModule: NAuthModule,
|
|
33
|
+
providers: [
|
|
34
|
+
{
|
|
35
|
+
provide: NAUTH_CLIENT_CONFIG,
|
|
36
|
+
useValue: config,
|
|
37
|
+
},
|
|
38
|
+
AngularHttpAdapter,
|
|
39
|
+
{
|
|
40
|
+
provide: AuthService,
|
|
41
|
+
useFactory: (httpAdapter) => {
|
|
42
|
+
return new AuthService(config, httpAdapter);
|
|
43
|
+
},
|
|
44
|
+
deps: [AngularHttpAdapter],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
provide: HTTP_INTERCEPTORS,
|
|
48
|
+
useClass: AuthInterceptorClass,
|
|
49
|
+
multi: true,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
55
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: NAuthModule, imports: [HttpClientModule], exports: [HttpClientModule] });
|
|
56
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NAuthModule, imports: [HttpClientModule, HttpClientModule] });
|
|
57
|
+
}
|
|
58
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NAuthModule, decorators: [{
|
|
59
|
+
type: NgModule,
|
|
60
|
+
args: [{
|
|
61
|
+
imports: [HttpClientModule],
|
|
62
|
+
exports: [HttpClientModule],
|
|
63
|
+
}]
|
|
64
|
+
}] });
|
|
65
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF1dGgubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL25nbW9kdWxlL25hdXRoLm1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUF1QixNQUFNLGVBQWUsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMzRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDOztBQUdoRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFLSCxNQUFNLE9BQU8sV0FBVztJQUN0QixNQUFNLENBQUMsT0FBTyxDQUFDLE1BQXlCO1FBQ3RDLE9BQU87WUFDTCxRQUFRLEVBQUUsV0FBVztZQUNyQixTQUFTLEVBQUU7Z0JBQ1Q7b0JBQ0UsT0FBTyxFQUFFLG1CQUFtQjtvQkFDNUIsUUFBUSxFQUFFLE1BQU07aUJBQ2pCO2dCQUNELGtCQUFrQjtnQkFDbEI7b0JBQ0UsT0FBTyxFQUFFLFdBQVc7b0JBQ3BCLFVBQVUsRUFBRSxDQUFDLFdBQStCLEVBQUUsRUFBRTt3QkFDOUMsT0FBTyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLENBQUM7b0JBQzlDLENBQUM7b0JBQ0QsSUFBSSxFQUFFLENBQUMsa0JBQWtCLENBQUM7aUJBQzNCO2dCQUNEO29CQUNFLE9BQU8sRUFBRSxpQkFBaUI7b0JBQzFCLFFBQVEsRUFBRSxvQkFBb0I7b0JBQzlCLEtBQUssRUFBRSxJQUFJO2lCQUNaO2FBQ0Y7U0FDRixDQUFDO0lBQ0osQ0FBQzt3R0F4QlUsV0FBVzt5R0FBWCxXQUFXLFlBSFosZ0JBQWdCLGFBQ2hCLGdCQUFnQjt5R0FFZixXQUFXLFlBSFosZ0JBQWdCLEVBQ2hCLGdCQUFnQjs7NEZBRWYsV0FBVztrQkFKdkIsUUFBUTttQkFBQztvQkFDUixPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDM0IsT0FBTyxFQUFFLENBQUMsZ0JBQWdCLENBQUM7aUJBQzVCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdNb2R1bGUsIE1vZHVsZVdpdGhQcm92aWRlcnMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEh0dHBDbGllbnRNb2R1bGUsIEhUVFBfSU5URVJDRVBUT1JTIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgTkFVVEhfQ0xJRU5UX0NPTkZJRyB9IGZyb20gJy4vdG9rZW5zJztcbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLnNlcnZpY2UnO1xuaW1wb3J0IHsgQW5ndWxhckh0dHBBZGFwdGVyIH0gZnJvbSAnLi9odHRwLWFkYXB0ZXInO1xuaW1wb3J0IHsgQXV0aEludGVyY2VwdG9yQ2xhc3MgfSBmcm9tICcuL2F1dGguaW50ZXJjZXB0b3IuY2xhc3MnO1xuaW1wb3J0IHsgTkF1dGhDbGllbnRDb25maWcgfSBmcm9tICdAbmF1dGgtdG9vbGtpdC9jbGllbnQnO1xuXG4vKipcbiAqIE5nTW9kdWxlIGZvciBuYXV0aC10b29sa2l0IEFuZ3VsYXIgaW50ZWdyYXRpb24uXG4gKlxuICogVXNlIHRoaXMgZm9yIE5nTW9kdWxlLWJhc2VkIGFwcHMgKEFuZ3VsYXIgMTcrIHdpdGggTmdNb2R1bGUgb3IgbGVnYWN5IGFwcHMpLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBhcHAubW9kdWxlLnRzXG4gKiBpbXBvcnQgeyBOQXV0aE1vZHVsZSB9IGZyb20gJ0BuYXV0aC10b29sa2l0L2NsaWVudC1hbmd1bGFyJztcbiAqXG4gKiBATmdNb2R1bGUoe1xuICogICBpbXBvcnRzOiBbXG4gKiAgICAgTkF1dGhNb2R1bGUuZm9yUm9vdCh7XG4gKiAgICAgICBiYXNlVXJsOiAnaHR0cDovL2xvY2FsaG9zdDozMDAwL2F1dGgnLFxuICogICAgICAgdG9rZW5EZWxpdmVyeTogJ2Nvb2tpZXMnLFxuICogICAgIH0pLFxuICogICBdLFxuICogfSlcbiAqIGV4cG9ydCBjbGFzcyBBcHBNb2R1bGUge31cbiAqIGBgYFxuICovXG5ATmdNb2R1bGUoe1xuICBpbXBvcnRzOiBbSHR0cENsaWVudE1vZHVsZV0sXG4gIGV4cG9ydHM6IFtIdHRwQ2xpZW50TW9kdWxlXSxcbn0pXG5leHBvcnQgY2xhc3MgTkF1dGhNb2R1bGUge1xuICBzdGF0aWMgZm9yUm9vdChjb25maWc6IE5BdXRoQ2xpZW50Q29uZmlnKTogTW9kdWxlV2l0aFByb3ZpZGVyczxOQXV0aE1vZHVsZT4ge1xuICAgIHJldHVybiB7XG4gICAgICBuZ01vZHVsZTogTkF1dGhNb2R1bGUsXG4gICAgICBwcm92aWRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHByb3ZpZGU6IE5BVVRIX0NMSUVOVF9DT05GSUcsXG4gICAgICAgICAgdXNlVmFsdWU6IGNvbmZpZyxcbiAgICAgICAgfSxcbiAgICAgICAgQW5ndWxhckh0dHBBZGFwdGVyLFxuICAgICAgICB7XG4gICAgICAgICAgcHJvdmlkZTogQXV0aFNlcnZpY2UsXG4gICAgICAgICAgdXNlRmFjdG9yeTogKGh0dHBBZGFwdGVyOiBBbmd1bGFySHR0cEFkYXB0ZXIpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgQXV0aFNlcnZpY2UoY29uZmlnLCBodHRwQWRhcHRlcik7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBkZXBzOiBbQW5ndWxhckh0dHBBZGFwdGVyXSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHByb3ZpZGU6IEhUVFBfSU5URVJDRVBUT1JTLFxuICAgICAgICAgIHVzZUNsYXNzOiBBdXRoSW50ZXJjZXB0b3JDbGFzcyxcbiAgICAgICAgICBtdWx0aTogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* Injection token for providing NAuthClientConfig in Angular apps.
|
|
4
|
+
*/
|
|
5
|
+
export const NAUTH_CLIENT_CONFIG = new InjectionToken('NAUTH_CLIENT_CONFIG');
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL25nbW9kdWxlL3Rva2Vucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRy9DOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxjQUFjLENBQW9CLHFCQUFxQixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3Rpb25Ub2tlbiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTkF1dGhDbGllbnRDb25maWcgfSBmcm9tICdAbmF1dGgtdG9vbGtpdC9jbGllbnQnO1xuXG4vKipcbiAqIEluamVjdGlvbiB0b2tlbiBmb3IgcHJvdmlkaW5nIE5BdXRoQ2xpZW50Q29uZmlnIGluIEFuZ3VsYXIgYXBwcy5cbiAqL1xuZXhwb3J0IGNvbnN0IE5BVVRIX0NMSUVOVF9DT05GSUcgPSBuZXcgSW5qZWN0aW9uVG9rZW48TkF1dGhDbGllbnRDb25maWc+KCdOQVVUSF9DTElFTlRfQ09ORklHJyk7XG4iXX0=
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API Surface of @nauth-toolkit/client-angular (NgModule)
|
|
3
|
+
*
|
|
4
|
+
* This is the default entry point for NgModule-based Angular apps.
|
|
5
|
+
* For standalone components, use: @nauth-toolkit/client-angular/standalone
|
|
6
|
+
*/
|
|
7
|
+
// Re-export core client types and utilities
|
|
8
|
+
export * from '@nauth-toolkit/client';
|
|
9
|
+
// Export NgModule-specific components (class-based)
|
|
10
|
+
export * from './ngmodule/tokens';
|
|
11
|
+
export * from './ngmodule/auth.service';
|
|
12
|
+
export * from './ngmodule/http-adapter';
|
|
13
|
+
export * from './ngmodule/auth.interceptor.class';
|
|
14
|
+
export * from './ngmodule/nauth.module';
|
|
15
|
+
// Export functional components (for flexibility in NgModule apps too)
|
|
16
|
+
export * from './lib/auth.interceptor';
|
|
17
|
+
export * from './lib/auth.guard';
|
|
18
|
+
export * from './lib/social-redirect-callback.guard';
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBRUgsNENBQTRDO0FBQzVDLGNBQWMsdUJBQXVCLENBQUM7QUFFdEMsb0RBQW9EO0FBQ3BELGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsbUNBQW1DLENBQUM7QUFDbEQsY0FBYyx5QkFBeUIsQ0FBQztBQUV4QyxzRUFBc0U7QUFDdEUsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsc0NBQXNDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBAbmF1dGgtdG9vbGtpdC9jbGllbnQtYW5ndWxhciAoTmdNb2R1bGUpXG4gKlxuICogVGhpcyBpcyB0aGUgZGVmYXVsdCBlbnRyeSBwb2ludCBmb3IgTmdNb2R1bGUtYmFzZWQgQW5ndWxhciBhcHBzLlxuICogRm9yIHN0YW5kYWxvbmUgY29tcG9uZW50cywgdXNlOiBAbmF1dGgtdG9vbGtpdC9jbGllbnQtYW5ndWxhci9zdGFuZGFsb25lXG4gKi9cblxuLy8gUmUtZXhwb3J0IGNvcmUgY2xpZW50IHR5cGVzIGFuZCB1dGlsaXRpZXNcbmV4cG9ydCAqIGZyb20gJ0BuYXV0aC10b29sa2l0L2NsaWVudCc7XG5cbi8vIEV4cG9ydCBOZ01vZHVsZS1zcGVjaWZpYyBjb21wb25lbnRzIChjbGFzcy1iYXNlZClcbmV4cG9ydCAqIGZyb20gJy4vbmdtb2R1bGUvdG9rZW5zJztcbmV4cG9ydCAqIGZyb20gJy4vbmdtb2R1bGUvYXV0aC5zZXJ2aWNlJztcbmV4cG9ydCAqIGZyb20gJy4vbmdtb2R1bGUvaHR0cC1hZGFwdGVyJztcbmV4cG9ydCAqIGZyb20gJy4vbmdtb2R1bGUvYXV0aC5pbnRlcmNlcHRvci5jbGFzcyc7XG5leHBvcnQgKiBmcm9tICcuL25nbW9kdWxlL25hdXRoLm1vZHVsZSc7XG5cbi8vIEV4cG9ydCBmdW5jdGlvbmFsIGNvbXBvbmVudHMgKGZvciBmbGV4aWJpbGl0eSBpbiBOZ01vZHVsZSBhcHBzIHRvbylcbmV4cG9ydCAqIGZyb20gJy4vbGliL2F1dGguaW50ZXJjZXB0b3InO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvYXV0aC5ndWFyZCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9zb2NpYWwtcmVkaXJlY3QtY2FsbGJhY2suZ3VhcmQnO1xuIl19
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public-api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF1dGgtdG9vbGtpdC1jbGllbnQtYW5ndWxhci1zcmMtc3RhbmRhbG9uZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdGFuZGFsb25lL25hdXRoLXRvb2xraXQtY2xpZW50LWFuZ3VsYXItc3JjLXN0YW5kYWxvbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API Surface of @nauth-toolkit/client-angular/standalone
|
|
3
|
+
*
|
|
4
|
+
* This entry point is for standalone component-based Angular apps (Angular 14+).
|
|
5
|
+
* For NgModule apps, use: @nauth-toolkit/client-angular
|
|
6
|
+
*
|
|
7
|
+
* NOTE: This simply re-exports the main entry point since both share the same code for now.
|
|
8
|
+
* The split allows future additions like `provideNAuth()` for standalone apps.
|
|
9
|
+
*/
|
|
10
|
+
// Re-export everything from the main entry point
|
|
11
|
+
export * from '@nauth-toolkit/client-angular';
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdGFuZGFsb25lL3B1YmxpYy1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0dBUUc7QUFFSCxpREFBaUQ7QUFDakQsY0FBYywrQkFBK0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIEBuYXV0aC10b29sa2l0L2NsaWVudC1hbmd1bGFyL3N0YW5kYWxvbmVcbiAqXG4gKiBUaGlzIGVudHJ5IHBvaW50IGlzIGZvciBzdGFuZGFsb25lIGNvbXBvbmVudC1iYXNlZCBBbmd1bGFyIGFwcHMgKEFuZ3VsYXIgMTQrKS5cbiAqIEZvciBOZ01vZHVsZSBhcHBzLCB1c2U6IEBuYXV0aC10b29sa2l0L2NsaWVudC1hbmd1bGFyXG4gKlxuICogTk9URTogVGhpcyBzaW1wbHkgcmUtZXhwb3J0cyB0aGUgbWFpbiBlbnRyeSBwb2ludCBzaW5jZSBib3RoIHNoYXJlIHRoZSBzYW1lIGNvZGUgZm9yIG5vdy5cbiAqIFRoZSBzcGxpdCBhbGxvd3MgZnV0dXJlIGFkZGl0aW9ucyBsaWtlIGBwcm92aWRlTkF1dGgoKWAgZm9yIHN0YW5kYWxvbmUgYXBwcy5cbiAqL1xuXG4vLyBSZS1leHBvcnQgZXZlcnl0aGluZyBmcm9tIHRoZSBtYWluIGVudHJ5IHBvaW50XG5leHBvcnQgKiBmcm9tICdAbmF1dGgtdG9vbGtpdC9jbGllbnQtYW5ndWxhcic7XG4iXX0=
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { inject } from '@angular/core';
|
|
2
|
+
import { Router } from '@angular/router';
|
|
3
|
+
import { AuthService } from './auth.service';
|
|
4
|
+
/**
|
|
5
|
+
* Functional route guard for authentication (Angular 17+).
|
|
6
|
+
*
|
|
7
|
+
* Protects routes by checking if user is authenticated.
|
|
8
|
+
* Redirects to login page if not authenticated.
|
|
9
|
+
*
|
|
10
|
+
* @param redirectTo - Path to redirect to if not authenticated (default: '/login')
|
|
11
|
+
* @returns CanActivateFn guard function
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // In route configuration
|
|
16
|
+
* const routes: Routes = [
|
|
17
|
+
* {
|
|
18
|
+
* path: 'home',
|
|
19
|
+
* component: HomeComponent,
|
|
20
|
+
* canActivate: [authGuard()]
|
|
21
|
+
* },
|
|
22
|
+
* {
|
|
23
|
+
* path: 'admin',
|
|
24
|
+
* component: AdminComponent,
|
|
25
|
+
* canActivate: [authGuard('/admin/login')]
|
|
26
|
+
* }
|
|
27
|
+
* ];
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function authGuard(redirectTo = '/login') {
|
|
31
|
+
return () => {
|
|
32
|
+
const auth = inject(AuthService);
|
|
33
|
+
const router = inject(Router);
|
|
34
|
+
if (auth.isAuthenticated()) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return router.createUrlTree([redirectTo]);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Class-based authentication guard for NgModule compatibility.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // In route configuration (NgModule)
|
|
46
|
+
* const routes: Routes = [
|
|
47
|
+
* {
|
|
48
|
+
* path: 'home',
|
|
49
|
+
* component: HomeComponent,
|
|
50
|
+
* canActivate: [AuthGuard]
|
|
51
|
+
* }
|
|
52
|
+
* ];
|
|
53
|
+
*
|
|
54
|
+
* // In module providers
|
|
55
|
+
* @NgModule({
|
|
56
|
+
* providers: [AuthGuard]
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export class AuthGuard {
|
|
61
|
+
auth;
|
|
62
|
+
router;
|
|
63
|
+
/**
|
|
64
|
+
* @param auth - Authentication service
|
|
65
|
+
* @param router - Angular router
|
|
66
|
+
*/
|
|
67
|
+
constructor(auth, router) {
|
|
68
|
+
this.auth = auth;
|
|
69
|
+
this.router = router;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if route can be activated.
|
|
73
|
+
*
|
|
74
|
+
* @returns True if authenticated, otherwise redirects to login
|
|
75
|
+
*/
|
|
76
|
+
canActivate() {
|
|
77
|
+
if (this.auth.isAuthenticated()) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
return this.router.createUrlTree(['/login']);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5ndWFyZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3N0YW5kYWxvbmUvYXV0aC5ndWFyZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZDLE9BQU8sRUFBaUIsTUFBTSxFQUFXLE1BQU0saUJBQWlCLENBQUM7QUFDakUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBeUJHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxVQUFVLEdBQUcsUUFBUTtJQUM3QyxPQUFPLEdBQXNCLEVBQUU7UUFDN0IsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ2pDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU5QixJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQzNCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFNVjtJQUNBO0lBTlY7OztPQUdHO0lBQ0gsWUFDVSxJQUFpQixFQUNqQixNQUFjO1FBRGQsU0FBSSxHQUFKLElBQUksQ0FBYTtRQUNqQixXQUFNLEdBQU4sTUFBTSxDQUFRO0lBQ3JCLENBQUM7SUFFSjs7OztPQUlHO0lBQ0gsV0FBVztRQUNULElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQy9DLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ2FuQWN0aXZhdGVGbiwgUm91dGVyLCBVcmxUcmVlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLnNlcnZpY2UnO1xuXG4vKipcbiAqIEZ1bmN0aW9uYWwgcm91dGUgZ3VhcmQgZm9yIGF1dGhlbnRpY2F0aW9uIChBbmd1bGFyIDE3KykuXG4gKlxuICogUHJvdGVjdHMgcm91dGVzIGJ5IGNoZWNraW5nIGlmIHVzZXIgaXMgYXV0aGVudGljYXRlZC5cbiAqIFJlZGlyZWN0cyB0byBsb2dpbiBwYWdlIGlmIG5vdCBhdXRoZW50aWNhdGVkLlxuICpcbiAqIEBwYXJhbSByZWRpcmVjdFRvIC0gUGF0aCB0byByZWRpcmVjdCB0byBpZiBub3QgYXV0aGVudGljYXRlZCAoZGVmYXVsdDogJy9sb2dpbicpXG4gKiBAcmV0dXJucyBDYW5BY3RpdmF0ZUZuIGd1YXJkIGZ1bmN0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEluIHJvdXRlIGNvbmZpZ3VyYXRpb25cbiAqIGNvbnN0IHJvdXRlczogUm91dGVzID0gW1xuICogICB7XG4gKiAgICAgcGF0aDogJ2hvbWUnLFxuICogICAgIGNvbXBvbmVudDogSG9tZUNvbXBvbmVudCxcbiAqICAgICBjYW5BY3RpdmF0ZTogW2F1dGhHdWFyZCgpXVxuICogICB9LFxuICogICB7XG4gKiAgICAgcGF0aDogJ2FkbWluJyxcbiAqICAgICBjb21wb25lbnQ6IEFkbWluQ29tcG9uZW50LFxuICogICAgIGNhbkFjdGl2YXRlOiBbYXV0aEd1YXJkKCcvYWRtaW4vbG9naW4nKV1cbiAqICAgfVxuICogXTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYXV0aEd1YXJkKHJlZGlyZWN0VG8gPSAnL2xvZ2luJyk6IENhbkFjdGl2YXRlRm4ge1xuICByZXR1cm4gKCk6IGJvb2xlYW4gfCBVcmxUcmVlID0+IHtcbiAgICBjb25zdCBhdXRoID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTtcbiAgICBjb25zdCByb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcblxuICAgIGlmIChhdXRoLmlzQXV0aGVudGljYXRlZCgpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gcm91dGVyLmNyZWF0ZVVybFRyZWUoW3JlZGlyZWN0VG9dKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBhdXRoZW50aWNhdGlvbiBndWFyZCBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gcm91dGUgY29uZmlndXJhdGlvbiAoTmdNb2R1bGUpXG4gKiBjb25zdCByb3V0ZXM6IFJvdXRlcyA9IFtcbiAqICAge1xuICogICAgIHBhdGg6ICdob21lJyxcbiAqICAgICBjb21wb25lbnQ6IEhvbWVDb21wb25lbnQsXG4gKiAgICAgY2FuQWN0aXZhdGU6IFtBdXRoR3VhcmRdXG4gKiAgIH1cbiAqIF07XG4gKlxuICogLy8gSW4gbW9kdWxlIHByb3ZpZGVyc1xuICogQE5nTW9kdWxlKHtcbiAqICAgcHJvdmlkZXJzOiBbQXV0aEd1YXJkXVxuICogfSlcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgQXV0aEd1YXJkIHtcbiAgLyoqXG4gICAqIEBwYXJhbSBhdXRoIC0gQXV0aGVudGljYXRpb24gc2VydmljZVxuICAgKiBAcGFyYW0gcm91dGVyIC0gQW5ndWxhciByb3V0ZXJcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYXV0aDogQXV0aFNlcnZpY2UsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiByb3V0ZSBjYW4gYmUgYWN0aXZhdGVkLlxuICAgKlxuICAgKiBAcmV0dXJucyBUcnVlIGlmIGF1dGhlbnRpY2F0ZWQsIG90aGVyd2lzZSByZWRpcmVjdHMgdG8gbG9naW5cbiAgICovXG4gIGNhbkFjdGl2YXRlKCk6IGJvb2xlYW4gfCBVcmxUcmVlIHtcbiAgICBpZiAodGhpcy5hdXRoLmlzQXV0aGVudGljYXRlZCgpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5yb3V0ZXIuY3JlYXRlVXJsVHJlZShbJy9sb2dpbiddKTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { inject, PLATFORM_ID } from '@angular/core';
|
|
2
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
3
|
+
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
4
|
+
import { Router } from '@angular/router';
|
|
5
|
+
import { catchError, switchMap, throwError, filter, take, BehaviorSubject, from } from 'rxjs';
|
|
6
|
+
import { NAUTH_CLIENT_CONFIG } from './tokens';
|
|
7
|
+
import { AuthService } from './auth.service';
|
|
8
|
+
/**
|
|
9
|
+
* Refresh state management.
|
|
10
|
+
* BehaviorSubject pattern is the industry-standard for token refresh.
|
|
11
|
+
*/
|
|
12
|
+
let isRefreshing = false;
|
|
13
|
+
const refreshTokenSubject = new BehaviorSubject(null);
|
|
14
|
+
/**
|
|
15
|
+
* Track retried requests to prevent infinite loops.
|
|
16
|
+
*/
|
|
17
|
+
const retriedRequests = new WeakSet();
|
|
18
|
+
/**
|
|
19
|
+
* Get CSRF token from cookie.
|
|
20
|
+
*/
|
|
21
|
+
function getCsrfToken(cookieName) {
|
|
22
|
+
if (typeof document === 'undefined')
|
|
23
|
+
return null;
|
|
24
|
+
const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
|
|
25
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Angular HTTP interceptor for nauth-toolkit.
|
|
29
|
+
*
|
|
30
|
+
* Handles:
|
|
31
|
+
* - Cookies mode: withCredentials + CSRF tokens + refresh via POST
|
|
32
|
+
* - JSON mode: refresh via SDK, retry with new token
|
|
33
|
+
*/
|
|
34
|
+
export const authInterceptor = (req, next) => {
|
|
35
|
+
const config = inject(NAUTH_CLIENT_CONFIG);
|
|
36
|
+
const http = inject(HttpClient);
|
|
37
|
+
const authService = inject(AuthService);
|
|
38
|
+
const platformId = inject(PLATFORM_ID);
|
|
39
|
+
const router = inject(Router);
|
|
40
|
+
const isBrowser = isPlatformBrowser(platformId);
|
|
41
|
+
if (!isBrowser) {
|
|
42
|
+
return next(req);
|
|
43
|
+
}
|
|
44
|
+
const tokenDelivery = config.tokenDelivery;
|
|
45
|
+
const baseUrl = config.baseUrl;
|
|
46
|
+
const endpoints = config.endpoints ?? {};
|
|
47
|
+
const refreshPath = endpoints.refresh ?? '/refresh';
|
|
48
|
+
const loginPath = endpoints.login ?? '/login';
|
|
49
|
+
const signupPath = endpoints.signup ?? '/signup';
|
|
50
|
+
const socialExchangePath = endpoints.socialExchange ?? '/social/exchange';
|
|
51
|
+
const refreshUrl = `${baseUrl}${refreshPath}`;
|
|
52
|
+
const isAuthApiRequest = req.url.includes(baseUrl);
|
|
53
|
+
const isRefreshEndpoint = req.url.includes(refreshPath);
|
|
54
|
+
const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);
|
|
55
|
+
// Build request with credentials (cookies mode only)
|
|
56
|
+
let authReq = req;
|
|
57
|
+
if (tokenDelivery === 'cookies') {
|
|
58
|
+
authReq = authReq.clone({ withCredentials: true });
|
|
59
|
+
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
|
|
60
|
+
const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';
|
|
61
|
+
const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';
|
|
62
|
+
const csrfToken = getCsrfToken(csrfCookieName);
|
|
63
|
+
if (csrfToken) {
|
|
64
|
+
authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return next(authReq).pipe(catchError((error) => {
|
|
69
|
+
const shouldHandle = error instanceof HttpErrorResponse &&
|
|
70
|
+
error.status === 401 &&
|
|
71
|
+
isAuthApiRequest &&
|
|
72
|
+
!isRefreshEndpoint &&
|
|
73
|
+
!isPublicEndpoint &&
|
|
74
|
+
!retriedRequests.has(req);
|
|
75
|
+
if (!shouldHandle) {
|
|
76
|
+
return throwError(() => error);
|
|
77
|
+
}
|
|
78
|
+
if (config.debug) {
|
|
79
|
+
console.warn('[nauth-interceptor] 401 detected:', req.url);
|
|
80
|
+
}
|
|
81
|
+
if (!isRefreshing) {
|
|
82
|
+
isRefreshing = true;
|
|
83
|
+
refreshTokenSubject.next(null);
|
|
84
|
+
if (config.debug) {
|
|
85
|
+
console.warn('[nauth-interceptor] Starting refresh...');
|
|
86
|
+
}
|
|
87
|
+
// Refresh based on mode
|
|
88
|
+
const refresh$ = tokenDelivery === 'cookies'
|
|
89
|
+
? http.post(refreshUrl, {}, { withCredentials: true })
|
|
90
|
+
: from(authService.refresh());
|
|
91
|
+
return refresh$.pipe(switchMap((response) => {
|
|
92
|
+
if (config.debug) {
|
|
93
|
+
console.warn('[nauth-interceptor] Refresh successful');
|
|
94
|
+
}
|
|
95
|
+
isRefreshing = false;
|
|
96
|
+
// Get new token (JSON mode) or signal success (cookies mode)
|
|
97
|
+
const newToken = 'accessToken' in response ? response.accessToken : 'success';
|
|
98
|
+
refreshTokenSubject.next(newToken ?? 'success');
|
|
99
|
+
// Build retry request
|
|
100
|
+
const retryReq = buildRetryRequest(authReq, tokenDelivery, newToken);
|
|
101
|
+
retriedRequests.add(retryReq);
|
|
102
|
+
if (config.debug) {
|
|
103
|
+
console.warn('[nauth-interceptor] Retrying:', req.url);
|
|
104
|
+
}
|
|
105
|
+
return next(retryReq);
|
|
106
|
+
}), catchError((err) => {
|
|
107
|
+
if (config.debug) {
|
|
108
|
+
console.error('[nauth-interceptor] Refresh failed:', err);
|
|
109
|
+
}
|
|
110
|
+
isRefreshing = false;
|
|
111
|
+
refreshTokenSubject.next(null);
|
|
112
|
+
// Handle session expiration - redirect to configured URL
|
|
113
|
+
if (config.redirects?.sessionExpired) {
|
|
114
|
+
router.navigateByUrl(config.redirects.sessionExpired).catch((navError) => {
|
|
115
|
+
if (config.debug) {
|
|
116
|
+
console.error('[nauth-interceptor] Navigation failed:', navError);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return throwError(() => err);
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Wait for ongoing refresh
|
|
125
|
+
if (config.debug) {
|
|
126
|
+
console.warn('[nauth-interceptor] Waiting for refresh...');
|
|
127
|
+
}
|
|
128
|
+
return refreshTokenSubject.pipe(filter((token) => token !== null), take(1), switchMap((token) => {
|
|
129
|
+
if (config.debug) {
|
|
130
|
+
console.warn('[nauth-interceptor] Refresh done, retrying:', req.url);
|
|
131
|
+
}
|
|
132
|
+
const retryReq = buildRetryRequest(authReq, tokenDelivery, token);
|
|
133
|
+
retriedRequests.add(retryReq);
|
|
134
|
+
return next(retryReq);
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
}));
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Build retry request with appropriate auth.
|
|
141
|
+
*/
|
|
142
|
+
function buildRetryRequest(originalReq, tokenDelivery, newToken) {
|
|
143
|
+
if (tokenDelivery === 'json' && newToken && newToken !== 'success') {
|
|
144
|
+
return originalReq.clone({
|
|
145
|
+
setHeaders: { Authorization: `Bearer ${newToken}` },
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return originalReq.clone();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Class-based interceptor for NgModule compatibility.
|
|
152
|
+
*/
|
|
153
|
+
export class AuthInterceptor {
|
|
154
|
+
intercept(req, next) {
|
|
155
|
+
return authInterceptor(req, next);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3N0YW5kYWxvbmUvYXV0aC5pbnRlcmNlcHRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQWlELFVBQVUsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3BILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFN0M7OztHQUdHO0FBQ0gsSUFBSSxZQUFZLEdBQUcsS0FBSyxDQUFDO0FBQ3pCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxlQUFlLENBQWdCLElBQUksQ0FBQyxDQUFDO0FBRXJFOztHQUVHO0FBQ0gsTUFBTSxlQUFlLEdBQUcsSUFBSSxPQUFPLEVBQXdCLENBQUM7QUFFNUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxVQUFrQjtJQUN0QyxJQUFJLE9BQU8sUUFBUSxLQUFLLFdBQVc7UUFBRSxPQUFPLElBQUksQ0FBQztJQUNqRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLFVBQVUsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUM5RSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsa0JBQWtCLENBQUMsS0FBSyxD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SSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDbkUsT0FBTyxXQUFXLENBQUMsS0FBSyxDQUFDO1lBQ3ZCLFVBQVUsRUFBRSxFQUFFLGFBQWEsRUFBRSxVQUFVLFFBQVEsRUFBRSxFQUFFO1NBQ3BELENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxPQUFPLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUM3QixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQUMxQixTQUFTLENBQUMsR0FBeUIsRUFBRSxJQUFtQjtRQUN0RCxPQUFPLGVBQWUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDcEMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgSHR0cEhhbmRsZXJGbiwgSHR0cEludGVyY2VwdG9yRm4sIEh0dHBSZXF1ZXN0LCBIdHRwQ2xpZW50LCBIdHRwRXJyb3JSZXNwb25zZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCBzd2l0Y2hNYXAsIHRocm93RXJyb3IsIGZpbHRlciwgdGFrZSwgQmVoYXZpb3JTdWJqZWN0LCBmcm9tIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBOQVVUSF9DTElFTlRfQ09ORklHIH0gZnJvbSAnLi90b2tlbnMnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuL2F1dGguc2VydmljZSc7XG5cbi8qKlxuICogUmVmcmVzaCBzdGF0ZSBtYW5hZ2VtZW50LlxuICogQmVoYXZpb3JTdWJqZWN0IHBhdHRlcm4gaXMgdGhlIGluZHVzdHJ5LXN0YW5kYXJkIGZvciB0b2tlbiByZWZyZXNoLlxuICovXG5sZXQgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG5jb25zdCByZWZyZXNoVG9rZW5TdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuLyoqXG4gKiBUcmFjayByZXRyaWVkIHJlcXVlc3RzIHRvIHByZXZlbnQgaW5maW5pdGUgbG9vcHMuXG4gKi9cbmNvbnN0IHJldHJpZWRSZXF1ZXN0cyA9IG5ldyBXZWFrU2V0PEh0dHBSZXF1ZXN0PHVua25vd24+PigpO1xuXG4vKipcbiAqIEdldCBDU1JGIHRva2VuIGZyb20gY29va2llLlxuICovXG5mdW5jdGlvbiBnZXRDc3JmVG9rZW4oY29va2llTmFtZTogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICh0eXBlb2YgZG9jdW1lbnQgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgbWF0Y2ggPSBkb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cChgKF58ICkke2Nvb2tpZU5hbWV9PShbXjtdKylgKSk7XG4gIHJldHVybiBtYXRjaCA/IGRlY29kZVVSSUNvbXBvbmVudChtYXRjaFsyXSkgOiBudWxsO1xufVxuXG4vKipcbiAqIEFuZ3VsYXIgSFRUUCBpbnRlcmNlcHRvciBmb3IgbmF1dGgtdG9vbGtpdC5cbiAqXG4gKiBIYW5kbGVzOlxuICogLSBDb29raWVzIG1vZGU6IHdpdGhDcmVkZW50aWFscyArIENTUkYgdG9rZW5zICsgcmVmcmVzaCB2aWEgUE9TVFxuICogLSBKU09OIG1vZGU6IHJlZnJlc2ggdmlhIFNESywgcmV0cnkgd2l0aCBuZXcgdG9rZW5cbiAqL1xuZXhwb3J0IGNvbnN0IGF1dGhJbnRlcmNlcHRvcjogSHR0cEludGVyY2VwdG9yRm4gPSAocmVxOiBIdHRwUmVxdWVzdDx1bmtub3duPiwgbmV4dDogSHR0cEhhbmRsZXJGbikgPT4ge1xuICBjb25zdCBjb25maWcgPSBpbmplY3QoTkFVVEhfQ0xJRU5UX0NPTkZJRyk7XG4gIGNvbnN0IGh0dHAgPSBpbmplY3QoSHR0cENsaWVudCk7XG4gIGNvbnN0IGF1dGhTZXJ2aWNlID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTtcbiAgY29uc3QgcGxhdGZvcm1JZCA9IGluamVjdChQTEFURk9STV9JRCk7XG4gIGNvbnN0IHJvdXRlciA9IGluamVjdChSb3V0ZXIpO1xuICBjb25zdCBpc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3NlcihwbGF0Zm9ybUlkKTtcblxuICBpZiAoIWlzQnJvd3Nlcikge1xuICAgIHJldHVybiBuZXh0KHJlcSk7XG4gIH1cblxuICBjb25zdCB0b2tlbkRlbGl2ZXJ5ID0gY29uZmlnLnRva2VuRGVsaXZlcnk7XG4gIGNvbnN0IGJhc2VVcmwgPSBjb25maWcuYmFzZVVybDtcbiAgY29uc3QgZW5kcG9pbnRzID0gY29uZmlnLmVuZHBvaW50cyA/PyB7fTtcbiAgY29uc3QgcmVmcmVzaFBhdGggPSBlbmRwb2ludHMucmVmcmVzaCA/PyAnL3JlZnJlc2gnO1xuICBjb25zdCBsb2dpblBhdGggPSBlbmRwb2ludHMubG9naW4gPz8gJy9sb2dpbic7XG4gIGNvbnN0IHNpZ251cFBhdGggPSBlbmRwb2ludHMuc2lnbnVwID8/ICcvc2lnbnVwJztcbiAgY29uc3Qgc29jaWFsRXhjaGFuZ2VQYXRoID0gZW5kcG9pbnRzLnNvY2lhbEV4Y2hhbmdlID8/ICcvc29jaWFsL2V4Y2hhbmdlJztcbiAgY29uc3QgcmVmcmVzaFVybCA9IGAke2Jhc2VVcmx9JHtyZWZyZXNoUGF0aH1gO1xuXG4gIGNvbnN0IGlzQXV0aEFwaVJlcXVlc3QgPSByZXEudXJsLmluY2x1ZGVzKGJhc2VVcmwpO1xuICBjb25zdCBpc1JlZnJlc2hFbmRwb2ludCA9IHJlcS51cmwuaW5jbHVkZXMocmVmcmVzaFBhdGgpO1xuICBjb25zdCBpc1B1YmxpY0VuZHBvaW50ID1cbiAgICByZXEudXJsLmluY2x1ZGVzKGxvZ2luUGF0aCkgfHwgcmVxLnVybC5pbmNsdWRlcyhzaWdudXBQYXRoKSB8fCByZXEudXJsLmluY2x1ZGVzKHNvY2lhbEV4Y2hhbmdlUGF0aCk7XG5cbiAgLy8gQnVpbGQgcmVxdWVzdCB3aXRoIGNyZWRlbnRpYWxzIChjb29raWVzIG1vZGUgb25seSlcbiAgbGV0IGF1dGhSZXEgPSByZXE7XG4gIGlmICh0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcycpIHtcbiAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHdpdGhDcmVkZW50aWFsczogdHJ1ZSB9KTtcblxuICAgIGlmIChbJ1BPU1QnLCAnUFVUJywgJ1BBVENIJywgJ0RFTEVURSddLmluY2x1ZGVzKHJlcS5tZXRob2QpKSB7XG4gICAgICBjb25zdCBjc3JmQ29va2llTmFtZSA9IGNvbmZpZy5jc3JmPy5jb29raWVOYW1lID8/ICduYXV0aF9jc3JmX3Rva2VuJztcbiAgICAgIGNvbnN0IGNzcmZIZWFkZXJOYW1lID0gY29uZmlnLmNzcmY/LmhlYWRlck5hbWUgPz8gJ3gtY3NyZi10b2tlbic7XG4gICAgICBjb25zdCBjc3JmVG9rZW4gPSBnZXRDc3JmVG9rZW4oY3NyZkNvb2tpZU5hbWUpO1xuICAgICAgaWYgKGNzcmZUb2tlbikge1xuICAgICAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHNldEhlYWRlcnM6IHsgW2NzcmZIZWFkZXJOYW1lXTogY3NyZlRva2VuIH0gfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5leHQoYXV0aFJlcSkucGlwZShcbiAgICBjYXRjaEVycm9yKChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgY29uc3Qgc2hvdWxkSGFuZGxlID1cbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBIdHRwRXJyb3JSZXNwb25zZSAmJlxuICAgICAgICBlcnJvci5zdGF0dXMgPT09IDQwMSAmJlxuICAgICAgICBpc0F1dGhBcGlSZXF1ZXN0ICYmXG4gICAgICAgICFpc1JlZnJlc2hFbmRwb2ludCAmJlxuICAgICAgICAhaXNQdWJsaWNFbmRwb2ludCAmJlxuICAgICAgICAhcmV0cmllZFJlcXVlc3RzLmhhcyhyZXEpO1xuXG4gICAgICBpZiAoIXNob3VsZEhhbmRsZSkge1xuICAgICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBlcnJvcik7XG4gICAgICB9XG5cbiAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIDQwMSBkZXRlY3RlZDonLCByZXEudXJsKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1JlZnJlc2hpbmcpIHtcbiAgICAgICAgaXNSZWZyZXNoaW5nID0gdHJ1ZTtcbiAgICAgICAgcmVmcmVzaFRva2VuU3ViamVjdC5uZXh0KG51bGwpO1xuXG4gICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oJ1tuYXV0aC1pbnRlcmNlcHRvcl0gU3RhcnRpbmcgcmVmcmVzaC4uLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVmcmVzaCBiYXNlZCBvbiBtb2RlXG4gICAgICAgIGNvbnN0IHJlZnJlc2gkID1cbiAgICAgICAgICB0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcydcbiAgICAgICAgICAgID8gaHR0cC5wb3N0PHsgYWNjZXNzVG9rZW4/OiBzdHJpbmcgfT4ocmVmcmVzaFVybCwge30sIHsgd2l0aENyZWRlbnRpYWxzOiB0cnVlIH0pXG4gICAgICAgICAgICA6IGZyb20oYXV0aFNlcnZpY2UucmVmcmVzaCgpKTtcblxuICAgICAgICByZXR1cm4gcmVmcmVzaCQucGlwZShcbiAgICAgICAgICBzd2l0Y2hNYXAoKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBSZWZyZXNoIHN1Y2Nlc3NmdWwnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlzUmVmcmVzaGluZyA9IGZhbHNlO1xuXG4gICAgICAgICAgICAvLyBHZXQgbmV3IHRva2VuIChKU09OIG1vZGUpIG9yIHNpZ25hbCBzdWNjZXNzIChjb29raWVzIG1vZGUpXG4gICAgICAgICAgICBjb25zdCBuZXdUb2tlbiA9ICdhY2Nlc3NUb2tlbicgaW4gcmVzcG9uc2UgPyByZXNwb25zZS5hY2Nlc3NUb2tlbiA6ICdzdWNjZXNzJztcbiAgICAgICAgICAgIHJlZnJlc2hUb2tlblN1YmplY3QubmV4dChuZXdUb2tlbiA/PyAnc3VjY2VzcycpO1xuXG4gICAgICAgICAgICAvLyBCdWlsZCByZXRyeSByZXF1ZXN0XG4gICAgICAgICAgICBjb25zdCByZXRyeVJlcSA9IGJ1aWxkUmV0cnlSZXF1ZXN0KGF1dGhSZXEsIHRva2VuRGVsaXZlcnksIG5ld1Rva2VuKTtcbiAgICAgICAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmV0cnlSZXEpO1xuXG4gICAgICAgICAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBSZXRyeWluZzonLCByZXEudXJsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBuZXh0KHJldHJ5UmVxKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBjYXRjaEVycm9yKChlcnIpID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignW25hdXRoLWludGVyY2VwdG9yXSBSZWZyZXNoIGZhaWxlZDonLCBlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG4gICAgICAgICAgICByZWZyZXNoVG9rZW5TdWJqZWN0Lm5leHQobnVsbCk7XG5cbiAgICAgICAgICAgIC8vIEhhbmRsZSBzZXNzaW9uIGV4cGlyYXRpb24gLSByZWRpcmVjdCB0byBjb25maWd1cmVkIFVSTFxuICAgICAgICAgICAgaWYgKGNvbmZpZy5yZWRpcmVjdHM/LnNlc3Npb25FeHBpcmVkKSB7XG4gICAgICAgICAgICAgIHJvdXRlci5uYXZpZ2F0ZUJ5VXJsKGNvbmZpZy5yZWRpcmVjdHMuc2Vzc2lvbkV4cGlyZWQpLmNhdGNoKChuYXZFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tuYXV0aC1pbnRlcmNlcHRvcl0gTmF2aWdhdGlvbiBmYWlsZWQ6JywgbmF2RXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycik7XG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBXYWl0IGZvciBvbmdvaW5nIHJlZnJlc2hcbiAgICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBXYWl0aW5nIGZvciByZWZyZXNoLi4uJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlZnJlc2hUb2tlblN1YmplY3QucGlwZShcbiAgICAgICAgICBmaWx0ZXIoKHRva2VuKTogdG9rZW4gaXMgc3RyaW5nID0+IHRva2VuICE9PSBudWxsKSxcbiAgICAgICAgICB0YWtlKDEpLFxuICAgICAgICAgIHN3aXRjaE1hcCgodG9rZW4pID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIFJlZnJlc2ggZG9uZSwgcmV0cnlpbmc6JywgcmVxLnVybCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCByZXRyeVJlcSA9IGJ1aWxkUmV0cnlSZXF1ZXN0KGF1dGhSZXEsIHRva2VuRGVsaXZlcnksIHRva2VuKTtcbiAgICAgICAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmV0cnlSZXEpO1xuICAgICAgICAgICAgcmV0dXJuIG5leHQocmV0cnlSZXEpO1xuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0pLFxuICApO1xufTtcblxuLyoqXG4gKiBCdWlsZCByZXRyeSByZXF1ZXN0IHdpdGggYXBwcm9wcmlhdGUgYXV0aC5cbiAqL1xuZnVuY3Rpb24gYnVpbGRSZXRyeVJlcXVlc3QoXG4gIG9yaWdpbmFsUmVxOiBIdHRwUmVxdWVzdDx1bmtub3duPixcbiAgdG9rZW5EZWxpdmVyeTogc3RyaW5nLFxuICBuZXdUb2tlbj86IHN0cmluZyxcbik6IEh0dHBSZXF1ZXN0PHVua25vd24+IHtcbiAgaWYgKHRva2VuRGVsaXZlcnkgPT09ICdqc29uJyAmJiBuZXdUb2tlbiAmJiBuZXdUb2tlbiAhPT0gJ3N1Y2Nlc3MnKSB7XG4gICAgcmV0dXJuIG9yaWdpbmFsUmVxLmNsb25lKHtcbiAgICAgIHNldEhlYWRlcnM6IHsgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke25ld1Rva2VufWAgfSxcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gb3JpZ2luYWxSZXEuY2xvbmUoKTtcbn1cblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBpbnRlcmNlcHRvciBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqL1xuZXhwb3J0IGNsYXNzIEF1dGhJbnRlcmNlcHRvciB7XG4gIGludGVyY2VwdChyZXE6IEh0dHBSZXF1ZXN0PHVua25vd24+LCBuZXh0OiBIdHRwSGFuZGxlckZuKSB7XG4gICAgcmV0dXJuIGF1dGhJbnRlcmNlcHRvcihyZXEsIG5leHQpO1xuICB9XG59XG4iXX0=
|