@molecule/app-angular 1.0.0
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/LICENSE +115 -0
- package/dist/i18n-reactive.d.ts +41 -0
- package/dist/i18n-reactive.d.ts.map +1 -0
- package/dist/i18n-reactive.js +46 -0
- package/dist/i18n-reactive.js.map +1 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/providers.d.ts +96 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +144 -0
- package/dist/providers.js.map +1 -0
- package/dist/services/async-state.service.d.ts +50 -0
- package/dist/services/async-state.service.d.ts.map +1 -0
- package/dist/services/async-state.service.js +109 -0
- package/dist/services/async-state.service.js.map +1 -0
- package/dist/services/auth.service.d.ts +105 -0
- package/dist/services/auth.service.d.ts.map +1 -0
- package/dist/services/auth.service.js +124 -0
- package/dist/services/auth.service.js.map +1 -0
- package/dist/services/capacitor-app.service.d.ts +46 -0
- package/dist/services/capacitor-app.service.d.ts.map +1 -0
- package/dist/services/capacitor-app.service.js +53 -0
- package/dist/services/capacitor-app.service.js.map +1 -0
- package/dist/services/change-password.service.d.ts +37 -0
- package/dist/services/change-password.service.d.ts.map +1 -0
- package/dist/services/change-password.service.js +34 -0
- package/dist/services/change-password.service.js.map +1 -0
- package/dist/services/device.service.d.ts +35 -0
- package/dist/services/device.service.d.ts.map +1 -0
- package/dist/services/device.service.js +29 -0
- package/dist/services/device.service.js.map +1 -0
- package/dist/services/forms.service.d.ts +237 -0
- package/dist/services/forms.service.d.ts.map +1 -0
- package/dist/services/forms.service.js +280 -0
- package/dist/services/forms.service.js.map +1 -0
- package/dist/services/http.service.d.ts +118 -0
- package/dist/services/http.service.d.ts.map +1 -0
- package/dist/services/http.service.js +171 -0
- package/dist/services/http.service.js.map +1 -0
- package/dist/services/i18n.service.d.ts +111 -0
- package/dist/services/i18n.service.d.ts.map +1 -0
- package/dist/services/i18n.service.js +135 -0
- package/dist/services/i18n.service.js.map +1 -0
- package/dist/services/index.d.ts +27 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +27 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/logger.service.d.ts +79 -0
- package/dist/services/logger.service.d.ts.map +1 -0
- package/dist/services/logger.service.js +110 -0
- package/dist/services/logger.service.js.map +1 -0
- package/dist/services/login.service.d.ts +37 -0
- package/dist/services/login.service.d.ts.map +1 -0
- package/dist/services/login.service.js +34 -0
- package/dist/services/login.service.js.map +1 -0
- package/dist/services/oauth.service.d.ts +110 -0
- package/dist/services/oauth.service.d.ts.map +1 -0
- package/dist/services/oauth.service.js +214 -0
- package/dist/services/oauth.service.js.map +1 -0
- package/dist/services/password-reset.service.d.ts +41 -0
- package/dist/services/password-reset.service.d.ts.map +1 -0
- package/dist/services/password-reset.service.js +45 -0
- package/dist/services/password-reset.service.js.map +1 -0
- package/dist/services/platform.service.d.ts +39 -0
- package/dist/services/platform.service.d.ts.map +1 -0
- package/dist/services/platform.service.js +33 -0
- package/dist/services/platform.service.js.map +1 -0
- package/dist/services/promise.service.d.ts +40 -0
- package/dist/services/promise.service.d.ts.map +1 -0
- package/dist/services/promise.service.js +85 -0
- package/dist/services/promise.service.js.map +1 -0
- package/dist/services/push.service.d.ts +45 -0
- package/dist/services/push.service.d.ts.map +1 -0
- package/dist/services/push.service.js +64 -0
- package/dist/services/push.service.js.map +1 -0
- package/dist/services/router.service.d.ts +114 -0
- package/dist/services/router.service.d.ts.map +1 -0
- package/dist/services/router.service.js +142 -0
- package/dist/services/router.service.js.map +1 -0
- package/dist/services/signup.service.d.ts +37 -0
- package/dist/services/signup.service.d.ts.map +1 -0
- package/dist/services/signup.service.js +34 -0
- package/dist/services/signup.service.js.map +1 -0
- package/dist/services/state.service.d.ts +82 -0
- package/dist/services/state.service.d.ts.map +1 -0
- package/dist/services/state.service.js +122 -0
- package/dist/services/state.service.js.map +1 -0
- package/dist/services/storage.service.d.ts +111 -0
- package/dist/services/storage.service.d.ts.map +1 -0
- package/dist/services/storage.service.js +167 -0
- package/dist/services/storage.service.js.map +1 -0
- package/dist/services/theme.service.d.ts +89 -0
- package/dist/services/theme.service.d.ts.map +1 -0
- package/dist/services/theme.service.js +116 -0
- package/dist/services/theme.service.js.map +1 -0
- package/dist/services/version.service.d.ts +44 -0
- package/dist/services/version.service.d.ts.map +1 -0
- package/dist/services/version.service.js +63 -0
- package/dist/services/version.service.js.map +1 -0
- package/dist/tokens.d.ts +47 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +39 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular service for logging.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Inject, Injectable } from '@angular/core';
|
|
7
|
+
import { LOGGER_PROVIDER } from '../tokens.js';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
/**
|
|
10
|
+
* Angular service for logging.
|
|
11
|
+
*
|
|
12
|
+
* Wraps molecule logger provider.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* @Component({
|
|
17
|
+
* selector: 'app-user-profile',
|
|
18
|
+
* template: `...`
|
|
19
|
+
* })
|
|
20
|
+
* export class UserProfileComponent implements OnInit, OnDestroy {
|
|
21
|
+
* private logger = this.loggerService.getLogger('UserProfileComponent')
|
|
22
|
+
*
|
|
23
|
+
* constructor(private loggerService: MoleculeLoggerService) {}
|
|
24
|
+
*
|
|
25
|
+
* ngOnInit() {
|
|
26
|
+
* this.logger.info('Component initialized')
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* ngOnDestroy() {
|
|
30
|
+
* this.logger.debug('Component destroyed')
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* handleError(error: Error) {
|
|
34
|
+
* this.logger.error('Operation failed', error)
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class MoleculeLoggerService {
|
|
40
|
+
constructor(provider) {
|
|
41
|
+
this.provider = provider;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get a logger instance.
|
|
45
|
+
*
|
|
46
|
+
* @param name - Logger name (usually component/service name)
|
|
47
|
+
* @returns The result.
|
|
48
|
+
*/
|
|
49
|
+
getLogger(name) {
|
|
50
|
+
return this.provider.getLogger(name);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create a logger with custom configuration.
|
|
54
|
+
*
|
|
55
|
+
* @param config - Logger configuration
|
|
56
|
+
* @returns The created instance.
|
|
57
|
+
*/
|
|
58
|
+
createLogger(config) {
|
|
59
|
+
return this.provider.createLogger(config);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Set the global log level.
|
|
63
|
+
*
|
|
64
|
+
* @param level - Log level
|
|
65
|
+
*/
|
|
66
|
+
setLevel(level) {
|
|
67
|
+
this.provider.setLevel(level);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the current global log level.
|
|
71
|
+
*
|
|
72
|
+
* @returns The result.
|
|
73
|
+
*/
|
|
74
|
+
getLevel() {
|
|
75
|
+
return this.provider.getLevel();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Enable logging.
|
|
79
|
+
*/
|
|
80
|
+
enable() {
|
|
81
|
+
this.provider.enable();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Disable logging.
|
|
85
|
+
*/
|
|
86
|
+
disable() {
|
|
87
|
+
this.provider.disable();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if logging is enabled.
|
|
91
|
+
*
|
|
92
|
+
* @returns Whether logging is enabled
|
|
93
|
+
*/
|
|
94
|
+
isEnabled() {
|
|
95
|
+
return this.provider.isEnabled();
|
|
96
|
+
}
|
|
97
|
+
static { this.ɵfac = function MoleculeLoggerService_Factory(__ngFactoryType__) { /* @ts-ignore */
|
|
98
|
+
return new (__ngFactoryType__ || MoleculeLoggerService)(i0.ɵɵinject(LOGGER_PROVIDER)); }; }
|
|
99
|
+
static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: MoleculeLoggerService, factory: MoleculeLoggerService.ɵfac, providedIn: 'root' }); }
|
|
100
|
+
}
|
|
101
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MoleculeLoggerService, [{
|
|
102
|
+
type: Injectable,
|
|
103
|
+
args: [{
|
|
104
|
+
providedIn: 'root',
|
|
105
|
+
}]
|
|
106
|
+
}], () => [{ type: undefined, decorators: [{
|
|
107
|
+
type: Inject,
|
|
108
|
+
args: [LOGGER_PROVIDER]
|
|
109
|
+
}] }], null); })();
|
|
110
|
+
//# sourceMappingURL=logger.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.service.js","sourceRoot":"","sources":["../../src/services/logger.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAIlD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,MAAM,OAAO,qBAAqB;IAChC,YAA6C,QAAwB;QAAxB,aAAQ,GAAR,QAAQ,CAAgB;IAAG,CAAC;IAEzE;;;;;OAKG;IACH,SAAS,CAAC,IAAa;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACtC,CAAC;IAED;;;;;OAKG;IACH,YAAY,CAAC,MAAoB;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;IAC3C,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,KAA+D;QACtE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC/B,CAAC;IAED;;;;OAIG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAA;IACjC,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAA;IACxB,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;IACzB,CAAC;IAED;;;;OAIG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAA;IAClC,CAAC;;qCA9DU,qBAAqB,cACZ,eAAe;uEADxB,qBAAqB,WAArB,qBAAqB,mBAFpB,MAAM;;iFAEP,qBAAqB;cAHjC,UAAU;eAAC;gBACV,UAAU,EAAE,MAAM;aACnB;;sBAEc,MAAM;uBAAC,eAAe"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular utility for login with async state tracking.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Observable } from 'rxjs';
|
|
7
|
+
import type { AuthClient, AuthResult, LoginCredentials } from '@molecule/app-auth';
|
|
8
|
+
import type { PromiseState } from '@molecule/app-utilities';
|
|
9
|
+
/**
|
|
10
|
+
* Login state manager.
|
|
11
|
+
*/
|
|
12
|
+
export interface LoginStateManager<T = unknown> {
|
|
13
|
+
state$: Observable<PromiseState<AuthResult<T>>>;
|
|
14
|
+
getState: () => PromiseState<AuthResult<T>>;
|
|
15
|
+
login: (credentials: LoginCredentials) => Promise<AuthResult<T>>;
|
|
16
|
+
reset: () => void;
|
|
17
|
+
destroy: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a login state manager with async state tracking.
|
|
21
|
+
*
|
|
22
|
+
* @param client - Auth client
|
|
23
|
+
* @returns Login state manager
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const loginManager = createLoginState(authClient)
|
|
28
|
+
*
|
|
29
|
+
* loginManager.state$.subscribe(state => {
|
|
30
|
+
* console.log(state.status) // 'idle' | 'pending' | 'resolved' | 'rejected'
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* await loginManager.login({ email: 'user@example.com', password: 'secret' })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function createLoginState<T = unknown>(client: AuthClient<T>): LoginStateManager<T>;
|
|
37
|
+
//# sourceMappingURL=login.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.service.d.ts","sourceRoot":"","sources":["../../src/services/login.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAI3D;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,OAAO;IAC5C,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/C,QAAQ,EAAE,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3C,KAAK,EAAE,CAAC,WAAW,EAAE,gBAAgB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IAChE,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAUzF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular utility for login with async state tracking.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { createPromiseState } from './promise.service.js';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a login state manager with async state tracking.
|
|
9
|
+
*
|
|
10
|
+
* @param client - Auth client
|
|
11
|
+
* @returns Login state manager
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const loginManager = createLoginState(authClient)
|
|
16
|
+
*
|
|
17
|
+
* loginManager.state$.subscribe(state => {
|
|
18
|
+
* console.log(state.status) // 'idle' | 'pending' | 'resolved' | 'rejected'
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* await loginManager.login({ email: 'user@example.com', password: 'secret' })
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function createLoginState(client) {
|
|
25
|
+
const manager = createPromiseState((credentials) => client.login(credentials));
|
|
26
|
+
return {
|
|
27
|
+
state$: manager.state$,
|
|
28
|
+
getState: manager.getState,
|
|
29
|
+
login: manager.call,
|
|
30
|
+
reset: manager.reset,
|
|
31
|
+
destroy: manager.destroy,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=login.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.service.js","sourceRoot":"","sources":["../../src/services/login.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAazD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAc,MAAqB;IACjE,MAAM,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAA6B,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAA;IAEhG,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,IAAI;QACnB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular utility for OAuth authentication.
|
|
3
|
+
*
|
|
4
|
+
* Builds provider initiation URLs, starts the full-page redirect flow, and
|
|
5
|
+
* automatically handles the OAuth callback: when the page loads with a `code`
|
|
6
|
+
* (+ optional `state`) URL parameter and a stashed provider, the code is
|
|
7
|
+
* exchanged for a session via `POST {baseURL}{loginEndpoint}`.
|
|
8
|
+
*
|
|
9
|
+
* Session establishment uses the auth client passed via
|
|
10
|
+
* {@link OAuthOptions.authClient} (inject the `AUTH_CLIENT` token and pass it
|
|
11
|
+
* through). Without a client, the code exchange itself has already
|
|
12
|
+
* established the httpOnly-cookie session server-side, so a user-carrying
|
|
13
|
+
* response still counts as a successful login.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { type Observable } from 'rxjs';
|
|
18
|
+
import type { AuthClient } from '@molecule/app-auth';
|
|
19
|
+
/**
|
|
20
|
+
* OAuth configuration options.
|
|
21
|
+
*/
|
|
22
|
+
export interface OAuthOptions {
|
|
23
|
+
/** Base URL for the API server (e.g. `https://api.example.com`). */
|
|
24
|
+
baseURL?: string;
|
|
25
|
+
/** List of supported OAuth provider names (e.g. `['github', 'google']`). */
|
|
26
|
+
oauthProviders?: string[];
|
|
27
|
+
/** Path prefix for OAuth initiation routes. Defaults to `/oauth`. */
|
|
28
|
+
oauthEndpoint?: string;
|
|
29
|
+
/** Path for the OAuth login POST endpoint. Defaults to `/users/log-in/oauth`. */
|
|
30
|
+
loginEndpoint?: string;
|
|
31
|
+
/** Called after a successful OAuth login (session established). */
|
|
32
|
+
onSuccess?: () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Called with a failure message when the OAuth login fails. Failures are
|
|
35
|
+
* also emitted on {@link OAuthStateManager.error$}.
|
|
36
|
+
*/
|
|
37
|
+
onError?: (error: string) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Auth client used to establish the session after the code exchange. This
|
|
40
|
+
* is THE way to wire session establishment in Angular: inject the
|
|
41
|
+
* `AUTH_CLIENT` token and pass the client here. When omitted, the helper
|
|
42
|
+
* falls back to the server-established httpOnly-cookie session (see
|
|
43
|
+
* {@link OAuthStateManager.handleCallback}).
|
|
44
|
+
*/
|
|
45
|
+
authClient?: AuthClient<unknown>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* OAuth state manager.
|
|
49
|
+
*/
|
|
50
|
+
export interface OAuthStateManager {
|
|
51
|
+
/** Observable of the configured OAuth provider names. */
|
|
52
|
+
providers$: Observable<string[]>;
|
|
53
|
+
/**
|
|
54
|
+
* Observable of OAuth failure messages (from the callback code exchange).
|
|
55
|
+
* Completed by {@link OAuthStateManager.destroy}.
|
|
56
|
+
*/
|
|
57
|
+
error$: Observable<string>;
|
|
58
|
+
/** Returns the configured OAuth provider names. */
|
|
59
|
+
getProviders: () => string[];
|
|
60
|
+
/** Builds the OAuth initiation URL for a provider. */
|
|
61
|
+
getOAuthUrl: (provider: string) => string;
|
|
62
|
+
/** Starts the full-page redirect flow for a provider. */
|
|
63
|
+
redirect: (provider: string) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Handles the OAuth callback: exchanges the `code` URL parameter for a
|
|
66
|
+
* session. Invoked automatically at creation (see {@link createOAuthState});
|
|
67
|
+
* exposed for callers that need to re-run it manually. No-ops unless
|
|
68
|
+
* running in a browser with a `code` URL parameter and a stashed provider.
|
|
69
|
+
*
|
|
70
|
+
* When an auth client was provided, the session is established locally
|
|
71
|
+
* (`setAccessToken` + `setUser` + `initialize`). When no client is
|
|
72
|
+
* available, the server has already established the httpOnly-cookie
|
|
73
|
+
* session during the exchange, so a user-carrying response still counts
|
|
74
|
+
* as success.
|
|
75
|
+
*/
|
|
76
|
+
handleCallback: () => Promise<void>;
|
|
77
|
+
/** Completes the `providers$` and `error$` observables. */
|
|
78
|
+
destroy: () => void;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Creates an OAuth state manager.
|
|
82
|
+
*
|
|
83
|
+
* Automatically handles OAuth callbacks: when created in a browser, it
|
|
84
|
+
* invokes {@link OAuthStateManager.handleCallback} immediately (a guarded
|
|
85
|
+
* no-op when the URL carries no `code` parameter).
|
|
86
|
+
*
|
|
87
|
+
* @param options - OAuth configuration
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const oauthManager = createOAuthState({
|
|
92
|
+
* baseURL: 'https://api.example.com',
|
|
93
|
+
* oauthProviders: ['github', 'google'],
|
|
94
|
+
* authClient: inject(AUTH_CLIENT),
|
|
95
|
+
* onSuccess: () => router.navigate(['/dashboard']),
|
|
96
|
+
* })
|
|
97
|
+
*
|
|
98
|
+
* oauthManager.providers$.subscribe(providers => {
|
|
99
|
+
* console.log(providers) // ['github', 'google']
|
|
100
|
+
* })
|
|
101
|
+
* oauthManager.error$.subscribe(error => {
|
|
102
|
+
* console.error(error)
|
|
103
|
+
* })
|
|
104
|
+
*
|
|
105
|
+
* const url = oauthManager.getOAuthUrl('github')
|
|
106
|
+
* ```
|
|
107
|
+
* @returns The created instance.
|
|
108
|
+
*/
|
|
109
|
+
export declare function createOAuthState(options?: OAuthOptions): OAuthStateManager;
|
|
110
|
+
//# sourceMappingURL=oauth.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.service.d.ts","sourceRoot":"","sources":["../../src/services/oauth.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAmB,KAAK,UAAU,EAAW,MAAM,MAAM,CAAA;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;IAChC;;;OAGG;IACH,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IAC1B,mDAAmD;IACnD,YAAY,EAAE,MAAM,MAAM,EAAE,CAAA;IAC5B,sDAAsD;IACtD,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAA;IACzC,yDAAyD;IACzD,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC;;;;;;;;;;;OAWG;IACH,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,2DAA2D;IAC3D,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAqL1E"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular utility for OAuth authentication.
|
|
3
|
+
*
|
|
4
|
+
* Builds provider initiation URLs, starts the full-page redirect flow, and
|
|
5
|
+
* automatically handles the OAuth callback: when the page loads with a `code`
|
|
6
|
+
* (+ optional `state`) URL parameter and a stashed provider, the code is
|
|
7
|
+
* exchanged for a session via `POST {baseURL}{loginEndpoint}`.
|
|
8
|
+
*
|
|
9
|
+
* Session establishment uses the auth client passed via
|
|
10
|
+
* {@link OAuthOptions.authClient} (inject the `AUTH_CLIENT` token and pass it
|
|
11
|
+
* through). Without a client, the code exchange itself has already
|
|
12
|
+
* established the httpOnly-cookie session server-side, so a user-carrying
|
|
13
|
+
* response still counts as a successful login.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
18
|
+
/**
|
|
19
|
+
* Creates an OAuth state manager.
|
|
20
|
+
*
|
|
21
|
+
* Automatically handles OAuth callbacks: when created in a browser, it
|
|
22
|
+
* invokes {@link OAuthStateManager.handleCallback} immediately (a guarded
|
|
23
|
+
* no-op when the URL carries no `code` parameter).
|
|
24
|
+
*
|
|
25
|
+
* @param options - OAuth configuration
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const oauthManager = createOAuthState({
|
|
30
|
+
* baseURL: 'https://api.example.com',
|
|
31
|
+
* oauthProviders: ['github', 'google'],
|
|
32
|
+
* authClient: inject(AUTH_CLIENT),
|
|
33
|
+
* onSuccess: () => router.navigate(['/dashboard']),
|
|
34
|
+
* })
|
|
35
|
+
*
|
|
36
|
+
* oauthManager.providers$.subscribe(providers => {
|
|
37
|
+
* console.log(providers) // ['github', 'google']
|
|
38
|
+
* })
|
|
39
|
+
* oauthManager.error$.subscribe(error => {
|
|
40
|
+
* console.error(error)
|
|
41
|
+
* })
|
|
42
|
+
*
|
|
43
|
+
* const url = oauthManager.getOAuthUrl('github')
|
|
44
|
+
* ```
|
|
45
|
+
* @returns The created instance.
|
|
46
|
+
*/
|
|
47
|
+
export function createOAuthState(options) {
|
|
48
|
+
const baseURL = options?.baseURL ?? '';
|
|
49
|
+
const oauthEndpoint = options?.oauthEndpoint ?? '/oauth';
|
|
50
|
+
const loginEndpoint = options?.loginEndpoint ?? '/users/log-in/oauth';
|
|
51
|
+
const providersList = options?.oauthProviders ?? [];
|
|
52
|
+
const authClient = options?.authClient ?? null;
|
|
53
|
+
const subject = new BehaviorSubject(providersList);
|
|
54
|
+
const errorSubject = new Subject();
|
|
55
|
+
const getOAuthUrl = (provider) => {
|
|
56
|
+
// Encode the provider as a single path segment so a (future) caller passing an
|
|
57
|
+
// untrusted value can never inject a path/query/scheme into the opened URL —
|
|
58
|
+
// defense-in-depth on top of the upstream static provider allowlist. Plain
|
|
59
|
+
// provider names ('github', 'google') pass through unchanged.
|
|
60
|
+
return `${baseURL}${oauthEndpoint}/${encodeURIComponent(provider)}`;
|
|
61
|
+
};
|
|
62
|
+
/** Stash which provider initiated the flow so the callback knows it's ours. */
|
|
63
|
+
const stashProvider = (provider) => {
|
|
64
|
+
try {
|
|
65
|
+
sessionStorage.setItem('oauth_provider', provider);
|
|
66
|
+
}
|
|
67
|
+
catch (_error) {
|
|
68
|
+
/* SSR-safe — sessionStorage is unavailable in SSR/sandboxed environments */
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Append the current page's PATH as `redirect_to` so the api's initiation
|
|
73
|
+
* endpoint (`GET /users/oauth/:provider`) builds a provider `redirect_uri`
|
|
74
|
+
* that lands the callback back on THIS page — the one where the manager is
|
|
75
|
+
* created (e.g. `/login`) — instead of the app root, where nothing may be
|
|
76
|
+
* listening for the `code` param. Path only (no origin/query): the server
|
|
77
|
+
* validates it as a same-origin absolute path, so it can never become an
|
|
78
|
+
* open redirect. Servers that predate the param simply ignore it.
|
|
79
|
+
*/
|
|
80
|
+
const withReturnPath = (url) => {
|
|
81
|
+
const path = typeof window !== 'undefined' ? window.location.pathname : '';
|
|
82
|
+
if (!path || path === '/')
|
|
83
|
+
return url;
|
|
84
|
+
return `${url}${url.includes('?') ? '&' : '?'}redirect_to=${encodeURIComponent(path)}`;
|
|
85
|
+
};
|
|
86
|
+
const redirect = (provider) => {
|
|
87
|
+
stashProvider(provider);
|
|
88
|
+
window.location.href = withReturnPath(getOAuthUrl(provider));
|
|
89
|
+
};
|
|
90
|
+
/** Surface a failure message via BOTH the onError callback and `error$`. */
|
|
91
|
+
const surfaceError = (error) => {
|
|
92
|
+
options?.onError?.(error);
|
|
93
|
+
errorSubject.next(error);
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Establish the authenticated session from an exchange result: seed the
|
|
97
|
+
* access token + user and let `initialize()` flip `authenticated`. Mirrors
|
|
98
|
+
* what `authClient.login()` does for password login. Returns whether a user
|
|
99
|
+
* was set (a result with no user is not a real session).
|
|
100
|
+
*/
|
|
101
|
+
const establishSession = async (client, token, user) => {
|
|
102
|
+
// Seed the token via the auth client's configured token storage adapter
|
|
103
|
+
// (in-memory by default) — NOT localStorage directly. Writing the bearer
|
|
104
|
+
// token to localStorage violates the in-memory-default storage contract and
|
|
105
|
+
// makes it JS-readable (XSS-exfiltratable).
|
|
106
|
+
if (token)
|
|
107
|
+
client.setAccessToken(token);
|
|
108
|
+
if (user && typeof user === 'object') {
|
|
109
|
+
client.setUser(user);
|
|
110
|
+
await client.initialize();
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
};
|
|
115
|
+
const handleCallback = async () => {
|
|
116
|
+
if (typeof window === 'undefined')
|
|
117
|
+
return;
|
|
118
|
+
const params = new URLSearchParams(window.location.search);
|
|
119
|
+
const code = params.get('code');
|
|
120
|
+
const state = params.get('state');
|
|
121
|
+
if (!code)
|
|
122
|
+
return;
|
|
123
|
+
// Retrieve the provider that initiated the flow
|
|
124
|
+
let provider = null;
|
|
125
|
+
try {
|
|
126
|
+
provider = sessionStorage.getItem('oauth_provider');
|
|
127
|
+
}
|
|
128
|
+
catch (_error) {
|
|
129
|
+
/* SSR-safe — sessionStorage is unavailable in SSR/sandboxed environments */
|
|
130
|
+
}
|
|
131
|
+
if (!provider)
|
|
132
|
+
return;
|
|
133
|
+
// Clean up URL (remove code/state params) and sessionStorage
|
|
134
|
+
const cleanUrl = new URL(window.location.href);
|
|
135
|
+
cleanUrl.searchParams.delete('code');
|
|
136
|
+
cleanUrl.searchParams.delete('state');
|
|
137
|
+
window.history.replaceState({}, '', cleanUrl.toString());
|
|
138
|
+
try {
|
|
139
|
+
sessionStorage.removeItem('oauth_provider');
|
|
140
|
+
}
|
|
141
|
+
catch (_error) {
|
|
142
|
+
/* SSR-safe — sessionStorage is unavailable in SSR/sandboxed environments */
|
|
143
|
+
}
|
|
144
|
+
// Exchange code for session
|
|
145
|
+
try {
|
|
146
|
+
const response = await fetch(`${baseURL}${loginEndpoint}`, {
|
|
147
|
+
method: 'POST',
|
|
148
|
+
headers: { 'Content-Type': 'application/json' },
|
|
149
|
+
credentials: 'include', // Send cookies (oauth_state) for state validation
|
|
150
|
+
body: JSON.stringify({
|
|
151
|
+
server: provider,
|
|
152
|
+
code,
|
|
153
|
+
state: state || undefined,
|
|
154
|
+
redirect_uri: window.location.origin,
|
|
155
|
+
}),
|
|
156
|
+
});
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
const data = (await response.json().catch(() => null));
|
|
159
|
+
surfaceError(data && typeof data.error === 'string' && data.error ? data.error : 'OAuth login failed');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const data = await response.json().catch(() => null);
|
|
163
|
+
// Store the token from the response
|
|
164
|
+
const authHeader = response.headers.get('authorization') || response.headers.get('set-authorization');
|
|
165
|
+
const token = authHeader ? authHeader.replace('Bearer ', '') : null;
|
|
166
|
+
// The authenticated user is `props` (molecule resource convention) or `user`
|
|
167
|
+
// (generic AuthResult). OAuth issues no refresh token, so we carry the token +
|
|
168
|
+
// user to whoever will own the session.
|
|
169
|
+
const user = data && typeof data === 'object'
|
|
170
|
+
? (data.props ??
|
|
171
|
+
data.user ??
|
|
172
|
+
null)
|
|
173
|
+
: null;
|
|
174
|
+
if (authClient) {
|
|
175
|
+
const ok = await establishSession(authClient, token, user);
|
|
176
|
+
if (ok)
|
|
177
|
+
options?.onSuccess?.();
|
|
178
|
+
else
|
|
179
|
+
surfaceError('OAuth login failed');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// No auth client available: the server already established the
|
|
183
|
+
// httpOnly-cookie session during the code exchange, so a user-carrying
|
|
184
|
+
// response still counts as a successful login. A response with no user
|
|
185
|
+
// means no session was established — surface the failure.
|
|
186
|
+
if (user && typeof user === 'object')
|
|
187
|
+
options?.onSuccess?.();
|
|
188
|
+
else
|
|
189
|
+
surfaceError('OAuth login failed');
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
surfaceError(err instanceof Error && err.message ? err.message : 'OAuth login failed');
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
// Auto-handle the OAuth callback at creation when running in a browser.
|
|
196
|
+
// handleCallback itself no-ops unless the URL carries a `code` param and a
|
|
197
|
+
// provider was stashed, so this is a guarded no-op on ordinary page loads.
|
|
198
|
+
if (typeof window !== 'undefined') {
|
|
199
|
+
void handleCallback();
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
providers$: subject.asObservable(),
|
|
203
|
+
error$: errorSubject.asObservable(),
|
|
204
|
+
getProviders: () => providersList,
|
|
205
|
+
getOAuthUrl,
|
|
206
|
+
redirect,
|
|
207
|
+
handleCallback,
|
|
208
|
+
destroy: () => {
|
|
209
|
+
subject.complete();
|
|
210
|
+
errorSubject.complete();
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=oauth.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.service.js","sourceRoot":"","sources":["../../src/services/oauth.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular utility for password reset with async state tracking.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Observable } from 'rxjs';
|
|
7
|
+
import type { AuthClient, PasswordResetConfirm, PasswordResetRequest } from '@molecule/app-auth';
|
|
8
|
+
import type { PromiseState } from '@molecule/app-utilities';
|
|
9
|
+
/**
|
|
10
|
+
* Password reset state manager.
|
|
11
|
+
*/
|
|
12
|
+
export interface PasswordResetStateManager {
|
|
13
|
+
requestState$: Observable<PromiseState<void>>;
|
|
14
|
+
confirmState$: Observable<PromiseState<void>>;
|
|
15
|
+
getRequestState: () => PromiseState<void>;
|
|
16
|
+
getConfirmState: () => PromiseState<void>;
|
|
17
|
+
requestReset: (data: PasswordResetRequest) => Promise<void>;
|
|
18
|
+
confirmReset: (data: PasswordResetConfirm) => Promise<void>;
|
|
19
|
+
reset: () => void;
|
|
20
|
+
destroy: () => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates a password reset state manager with async state tracking.
|
|
24
|
+
*
|
|
25
|
+
* @param client - Auth client
|
|
26
|
+
* @returns Password reset state manager
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const resetManager = createPasswordResetState(authClient)
|
|
31
|
+
*
|
|
32
|
+
* resetManager.requestState$.subscribe(state => {
|
|
33
|
+
* console.log(state.status) // 'idle' | 'pending' | 'resolved' | 'rejected'
|
|
34
|
+
* })
|
|
35
|
+
*
|
|
36
|
+
* await resetManager.requestReset({ email: 'user@example.com' })
|
|
37
|
+
* await resetManager.confirmReset({ token: 'abc123', password: 'newpass' })
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function createPasswordResetState(client: AuthClient): PasswordResetStateManager;
|
|
41
|
+
//# sourceMappingURL=password-reset.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset.service.d.ts","sourceRoot":"","sources":["../../src/services/password-reset.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAChG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAI3D;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;IAC7C,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;IAC7C,eAAe,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,CAAA;IACzC,eAAe,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,CAAA;IACzC,YAAY,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,YAAY,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,yBAAyB,CAyBtF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular utility for password reset with async state tracking.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { createPromiseState } from './promise.service.js';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a password reset state manager with async state tracking.
|
|
9
|
+
*
|
|
10
|
+
* @param client - Auth client
|
|
11
|
+
* @returns Password reset state manager
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const resetManager = createPasswordResetState(authClient)
|
|
16
|
+
*
|
|
17
|
+
* resetManager.requestState$.subscribe(state => {
|
|
18
|
+
* console.log(state.status) // 'idle' | 'pending' | 'resolved' | 'rejected'
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* await resetManager.requestReset({ email: 'user@example.com' })
|
|
22
|
+
* await resetManager.confirmReset({ token: 'abc123', password: 'newpass' })
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function createPasswordResetState(client) {
|
|
26
|
+
const requestManager = createPromiseState((data) => client.requestPasswordReset(data));
|
|
27
|
+
const confirmManager = createPromiseState((data) => client.confirmPasswordReset(data));
|
|
28
|
+
return {
|
|
29
|
+
requestState$: requestManager.state$,
|
|
30
|
+
confirmState$: confirmManager.state$,
|
|
31
|
+
getRequestState: requestManager.getState,
|
|
32
|
+
getConfirmState: confirmManager.getState,
|
|
33
|
+
requestReset: requestManager.call,
|
|
34
|
+
confirmReset: confirmManager.call,
|
|
35
|
+
reset: () => {
|
|
36
|
+
requestManager.reset();
|
|
37
|
+
confirmManager.reset();
|
|
38
|
+
},
|
|
39
|
+
destroy: () => {
|
|
40
|
+
requestManager.destroy();
|
|
41
|
+
confirmManager.destroy();
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=password-reset.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset.service.js","sourceRoot":"","sources":["../../src/services/password-reset.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAgBzD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAkB;IACzD,MAAM,cAAc,GAAG,kBAAkB,CAAC,CAAC,IAA0B,EAAE,EAAE,CACvE,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAClC,CAAA;IAED,MAAM,cAAc,GAAG,kBAAkB,CAAC,CAAC,IAA0B,EAAE,EAAE,CACvE,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAClC,CAAA;IAED,OAAO;QACL,aAAa,EAAE,cAAc,CAAC,MAAM;QACpC,aAAa,EAAE,cAAc,CAAC,MAAM;QACpC,eAAe,EAAE,cAAc,CAAC,QAAQ;QACxC,eAAe,EAAE,cAAc,CAAC,QAAQ;QACxC,YAAY,EAAE,cAAc,CAAC,IAAI;QACjC,YAAY,EAAE,cAAc,CAAC,IAAI;QACjC,KAAK,EAAE,GAAG,EAAE;YACV,cAAc,CAAC,KAAK,EAAE,CAAA;YACtB,cAAc,CAAC,KAAK,EAAE,CAAA;QACxB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE;YACZ,cAAc,CAAC,OAAO,EAAE,CAAA;YACxB,cAAc,CAAC,OAAO,EAAE,CAAA;QAC1B,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular platform service for accessing platform information.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Platform } from '@molecule/app-platform';
|
|
7
|
+
/**
|
|
8
|
+
* Platform service interface.
|
|
9
|
+
*/
|
|
10
|
+
export interface PlatformService {
|
|
11
|
+
platform: Platform;
|
|
12
|
+
isNative: boolean;
|
|
13
|
+
isMobile: boolean;
|
|
14
|
+
isDesktop: boolean;
|
|
15
|
+
isWeb: boolean;
|
|
16
|
+
isDevelopment: boolean;
|
|
17
|
+
isProduction: boolean;
|
|
18
|
+
isPlatform: (...platforms: Platform[]) => boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates an Angular platform service with static platform information.
|
|
22
|
+
*
|
|
23
|
+
* @returns Platform service with platform flags and isPlatform check
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const platform = createPlatformService()
|
|
28
|
+
*
|
|
29
|
+
* if (platform.isMobile) {
|
|
30
|
+
* console.log('Running on mobile')
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* if (platform.isPlatform('ios', 'android')) {
|
|
34
|
+
* console.log('Running on iOS or Android')
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare const createPlatformService: () => PlatformService;
|
|
39
|
+
//# sourceMappingURL=platform.service.d.ts.map
|