{"id":20173552,"url":"https://github.com/ronasit/angular-common","last_synced_at":"2025-06-16T09:32:42.448Z","repository":{"id":38115555,"uuid":"244812858","full_name":"RonasIT/angular-common","owner":"RonasIT","description":null,"archived":false,"fork":false,"pushed_at":"2024-09-10T09:53:24.000Z","size":2927,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T03:17:32.314Z","etag":null,"topics":["angular"],"latest_commit_sha":null,"homepage":"https://ronasit.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RonasIT.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-04T05:09:51.000Z","updated_at":"2024-09-10T09:48:31.000Z","dependencies_parsed_at":"2024-11-14T01:47:21.563Z","dependency_job_id":null,"html_url":"https://github.com/RonasIT/angular-common","commit_stats":null,"previous_names":[],"tags_count":65,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RonasIT%2Fangular-common","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RonasIT%2Fangular-common/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RonasIT%2Fangular-common/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RonasIT%2Fangular-common/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RonasIT","download_url":"https://codeload.github.com/RonasIT/angular-common/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248148247,"owners_count":21055548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular"],"created_at":"2024-11-14T01:36:37.413Z","updated_at":"2025-04-10T03:17:40.538Z","avatar_url":"https://github.com/RonasIT.png","language":"TypeScript","readme":"# Ronas IT Angular Common\r\n\r\nCommon Angular services for communicating with backend, authentication and user managing.\r\n\r\n## Live demo\r\n\r\nIn progress...\r\n\r\n## About the library\r\n\r\n__Ronas IT Angular Common__ working with cookies. One of the main advantages of this approach is that cookies can be HTTP-only. It makes them read-protected on the client side, that improves safety against any Cross-site scripting (XSS) attacks. Cookie-based authentication allows using this services in Server-Side Rendering (SSR) applications.\r\n\r\n## Getting Started\r\n\r\n### Installation\r\n\r\nInstall Ronas IT Angular Common:\r\n\r\n```bash\r\nnpm i @ronas-it/angular-common --save\r\n```\r\n\r\n### Usage\r\n\r\n#### ApiModule\r\n\r\n1. Add `ApiModule` to `AppModule` imports:\r\n\r\n```ts\r\nimport { ApiModule } from '@ronas-it/angular-common';\r\nimport { configuration } from '@configuration';\r\n\r\n@NgModule({\r\n  imports: [\r\n    ApiModule.forRoot({\r\n      apiUrl: configuration.api.url\r\n    }),\r\n    ...\r\n  ],\r\n  ...\r\n})\r\nexport class AppModule { }\r\n```\r\n\r\n2. Inject `ApiService` and use it:\r\n\r\n```ts\r\nimport { ApiService } from '@ronas-it/angular-common';\r\nimport { Injectable } from '@angular/core';\r\n\r\n@Injectable()\r\nexport class ProductService {\r\n  constructor(\r\n    private apiService: ApiService\r\n  ) { }\r\n\r\n  public delete(id: number): Observable\u003cvoid\u003e {\r\n    return this.apiService.delete(`/products/${id}`);\r\n  }\r\n\r\n  ...\r\n}\r\n```\r\n\r\n#### CookieModule\r\n\r\n1. Add `CookieModule` to `AppModule` imports:\r\n\r\n```ts\r\nimport { CookieModule } from '@ronas-it/angular-common';\r\n\r\n@NgModule({\r\n  imports: [\r\n    CookieModule.forRoot({\r\n      defaultOptions: { path: '/', /* other cookie options ... */ }\r\n    }),\r\n    ...\r\n  ],\r\n  ...\r\n})\r\nexport class AppModule { }\r\n```\r\n\r\n2. Inject `CookieService` and use it:\r\n\r\n```ts\r\nimport { BehaviorSubject, Subject } from 'rxjs';\r\nimport { CookieService } from '@ronas-it/angular-common';\r\nimport { Injectable } from '@angular/core';\r\n\r\n@Injectable()\r\nexport class CookiePopupFacade {\r\n  private isCookiesAccepted$: Subject\u003cboolean\u003e;\r\n\r\n  constructor(\r\n    private cookieService: CookieService\r\n  ) { \r\n    this.isCookiesAccepted$ = new BehaviorSubject(this.cookieService.get('isCookiesAccepted') === 'true');\r\n  }\r\n\r\n  public acceptCookies(): void {\r\n    this.isCookiesAccepted$.next(true);\r\n\r\n    this.cookieService.put('isCookiesAccepted', 'true', { maxAge: 4e10 });\r\n  }\r\n\r\n  ...\r\n}\r\n```\r\n\r\n3. (SSR Only) Add providers for `REQUEST` and `RESPONSE` injection tokens from\r\n`@nguniversal/express-engine/tokens` in `server.ts`:\r\n\r\n```ts\r\nserver.get('*', (req, res) =\u003e {\r\n  res.render(indexHtml, {\r\n    req,\r\n    res,\r\n    providers: [\r\n      {\r\n        provide: APP_BASE_HREF,\r\n        useValue: req.baseUrl\r\n      },\r\n      {\r\n        provide: REQUEST,\r\n        useValue: req\r\n      },\r\n      {\r\n        provide: RESPONSE,\r\n        useValue: res\r\n      }\r\n    ]\r\n  });\r\n});\r\n```\r\n\r\n4. (SSR Only) Set `requestToken` and `responseToken` parameters in the `CookieModule` config:\r\n\r\n```ts\r\nimport { CookieModule } from '@ronas-it/angular-common';\r\nimport { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';\r\n\r\n@NgModule({\r\n  imports: [\r\n    CookieModule.forRoot({\r\n      defaultOptions: { /* ... */ },\r\n      requestToken: REQUEST,\r\n      responseToken: RESPONSE\r\n    }),\r\n    ...\r\n  ],\r\n  ...\r\n})\r\nexport class AppModule { }\r\n```\r\n\r\n#### UserModule\r\n\r\n_Note: This module depends on `ApiModule` and `AuthModule`. Please make sure to\r\ninstall them prior to installing this module._\r\n\r\n1. Create a `User` model and extend it from `AbstractUser`:\r\n\r\n```ts\r\nimport { AbstractUser } from '@ronas-it/angular-common';\r\nimport { Expose } from 'class-transformer';\r\n\r\nexport class User extends AbstractUser {\r\n  @Expose({ groups: ['main'] })\r\n  public id: number;\r\n\r\n  @Expose({ groups: ['main'] })\r\n  public name: string;\r\n\r\n  @Expose({ groups: ['main'] })\r\n  public email: string;\r\n}\r\n```\r\n\r\n2. Create a `UserService` and extend it from `CommonUserService`:\r\n\r\n```ts\r\nimport { UserService as CommonUserService } from '@ronas-it/angular-common';\r\n\r\n@Injectable()\r\nexport class UserService extends CommonUserService\u003cUser\u003e {\r\n  /* Define custom methods or override existing methods here. */\r\n}\r\n```\r\n\r\n3. Create a `UserModule` and add `CommonUserModule` to imports:\r\n\r\n```ts\r\nimport { NgModule } from '@angular/core';\r\nimport { User } from './models';\r\nimport { UserModule as CommonUserModule } from '@ronas-it/angular-common';\r\nimport { UserService } from './user.service';\r\n\r\n@NgModule({\r\n  imports: [\r\n    CommonUserModule.forRoot({\r\n      userModel: User,\r\n      userService: UserService\r\n    }),\r\n    ...\r\n  ],\r\n  ...\r\n})\r\nexport class UserModule { }\r\n```\r\n\r\n4. Inject `UserService` and use it:\r\n\r\n```ts\r\nimport { Action } from '@ngrx/store';\r\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\r\nimport { AuthService } from '@shared/auth';\r\nimport { catchError, filter, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators';\r\nimport { HttpErrorResponse } from '@angular/common/http';\r\nimport { Injectable } from '@angular/core';\r\nimport { Observable, of } from 'rxjs';\r\nimport { User } from '../models';\r\nimport { userActions } from './actions';\r\nimport { UserService } from '../user.service';\r\n\r\n@Injectable()\r\nexport class UserEffects {\r\n  public refreshProfile$: Observable\u003cAction\u003e = createEffect(\r\n    () =\u003e this.actions$.pipe(\r\n      ofType(userActions.refreshProfile),\r\n      withLatestFrom(this.authService.isAuthenticated$),\r\n      filter(([_, isAuthenticated]) =\u003e isAuthenticated),\r\n      switchMap(() =\u003e {\r\n        return this.userService.refreshProfile()\r\n          .pipe(\r\n            mergeMap((user: User) =\u003e [\r\n              userActions.updateProfile({ profile: user }),\r\n              userActions.refreshProfileSuccess()\r\n            ]),\r\n            catchError((response: HttpErrorResponse) =\u003e of(userActions.refreshProfileFailure({ response })))\r\n          );\r\n      })\r\n    )\r\n  );\r\n\r\n  constructor(\r\n    private actions$: Actions,\r\n    private authService: AuthService,\r\n    private userService: UserService\r\n  ) { }\r\n}\r\n```\r\n\r\n#### AuthModule\r\n\r\n_Note: This module depends on `ApiModule`, `CookieModule` and `UserModule`. Please make sure to\r\ninstall them prior to installing this module._\r\n\r\n1. Create an `AuthService` and extend it from `CommonAuthService`:\r\n\r\n```ts\r\nimport { AuthService as CommonAuthService } from '@ronas-it/angular-common';\r\nimport { Injectable } from '@angular/core';\r\nimport { User } from '@shared/user';\r\n\r\n@Injectable()\r\nexport class AuthService extends CommonAuthService\u003cUser\u003e {\r\n  /* Define custom methods or override existing methods here. */\r\n}\r\n```\r\n\r\n2. Create an `AuthModule` and add `CommonAuthModule` to imports:\r\n\r\n```ts\r\nimport { AuthModule as CommonAuthModule } from '@ronas-it/angular-common';\r\nimport { AuthService } from './auth.service';\r\nimport { configuration } from '@configuration';\r\nimport { NgModule } from '@angular/core';\r\n\r\n@NgModule({\r\n  imports: [\r\n    CommonAuthModule.forRoot({\r\n      unauthorizedRoutes: configuration.api.unauthorized_routes,\r\n      authService: AuthService,\r\n\r\n      // Optionally, you can pass `unauthenticatedRoute` parameter that\r\n      // specifies the route to redirect to after logout or when a user is\r\n      // not authenticated to view some page. By default it is set to `/login`.\r\n      unauthenticatedRoute: '/'\r\n    }),\r\n    ...\r\n  ],\r\n  ...\r\n})\r\nexport class AuthModule { }\r\n```\r\n\r\n3. Inject `AuthService` and use it:\r\n\r\n```ts\r\nimport { Action } from '@ngrx/store';\r\nimport { Actions, createEffect, ofType } from '@ngrx/effects';\r\nimport { authActions } from './actions';\r\nimport { AuthService } from '../auth.service';\r\nimport { catchError, exhaustMap, map } from 'rxjs/operators';\r\nimport { Injectable } from '@angular/core';\r\nimport { Observable, of } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class AuthEffects {\r\n  public authorize$: Observable\u003cAction\u003e = createEffect(\r\n    () =\u003e this.actions$.pipe(\r\n      ofType(authActions.authorize),\r\n      exhaustMap((action) =\u003e {\r\n        return this.authService\r\n          .authorize(action.credentials)\r\n          .pipe(\r\n            map((response) =\u003e authActions.authSuccess({ response })),\r\n            catchError((response) =\u003e of(authActions.authFailure({ response })))\r\n          );\r\n      })\r\n    )\r\n  );\r\n\r\n  constructor(\r\n    private actions$: Actions,\r\n    private authService: AuthService\r\n  ) { }\r\n}\r\n```\r\n\r\n## API\r\n\r\n### ApiModule\r\n\r\n#### Config\r\n\r\n```ts\r\nApiModule.forRoot(config: ApiConfig)\r\n```\r\n\r\n##### ApiConfig\r\n\r\nName | Type | Required | Description\r\n--- | --- | --- | ---\r\n`apiUrl` | `string` | Yes | Endpoint that allows you to access an API\r\n`trailingSlash` | `boolean` | No | The need for trailing slash (`https://api.your-service.com/login/` for example)\r\n`enableArrayKeys` | `boolean` | No | Enabling array keys for http params\r\n`fileKeys` | `Array\u003cstring\u003e` | No | List of the file keys for http params\r\n\r\n#### ApiService\r\n\r\nField | Type\r\n--- | --- \r\n`apiUrl` | `string`\r\n`trailingSlash` | `string`\r\n`fileKeys` | `Array\u003cstring\u003e`\r\n\r\nMethod | Arguments | Return type\r\n--- | --- | --- \r\n`get\u003cT\u003e` | `endpoint: string, params: any, options: object` | `Observable\u003cT\u003e` \r\n`post\u003cT\u003e` | `endpoint: string, data: any, options: object` | `Observable\u003cT\u003e` \r\n`put\u003cT\u003e` | `endpoint: string, data: any, options: object` | `Observable\u003cT\u003e` \r\n`delete\u003cT\u003e` | `endpoint: string, params: any, options: object` | `Observable\u003cT\u003e` \r\n\r\n### CookieModule\r\n\r\n#### Config\r\n\r\n```ts\r\nCookieModule.forRoot(config: CookieConfig)\r\n```\r\n\r\n##### CookieConfig\r\n\r\nName | Type | Required | Description\r\n--- | --- | --- | ---\r\n`defaultOptions` | `CookieOptions` | No | Cookie options that will be used if not specified in the `put` method \r\n`requestToken` | `InjectionToken\u003cRequest\u003e` | No | `Request` injection token from `@nguniversal/express-engine/tokens` for cookies support in SSR\r\n`responseToken` | `InjectionToken\u003cResponse\u003e` | No | `Response` injection token from `@nguniversal/express-engine/tokens` for cookies support in SSR\r\n\r\n##### CookieOptions\r\n\r\nName | Type\r\n--- | ---\r\n`maxAge` | `number`\r\n`expires` | `Date`\r\n`path` | `string`\r\n`domain` | `string`\r\n`secure` | `boolean`\r\n`sameSite` | `boolean \\| 'lax' \\| 'strict' \\| 'none'`\r\n\r\n#### CookieService\\\u003cTKey extends string = string\u003e\r\n\r\nField | Type\r\n--- | --- \r\n`cookieString` | `string`\r\n\r\nMethod | Arguments | Return type\r\n--- | --- | --- \r\n`get` | `key: TKey` | `string \\| null` \r\n`getObject` | `key: TKey` | `object \\| null` \r\n`getAll` | | `Record\u003cstring, string\u003e` \r\n`hasKey` | `key: TKey` | `boolean` \r\n`put` | `key: TKey, value: string, options?: CookieOptions` | `void`\r\n`putObject` | `key: TKey, value: object, options?: CookieOptions` | `void`\r\n`remove` | `key: TKey, options?: CookieOptions` | `void`\r\n`removeAll` | `options?: CookieOptions` | `void`\r\n\r\n### AuthModule\r\n\r\n#### Config\r\n\r\n```ts\r\nCommonAuthModule.forRoot(config: AuthConfig)\r\n```\r\n\r\n##### AuthConfig\r\n\r\nName | Type | Required | Description\r\n--- | --- | --- | ---\r\n`unauthorizedRoutes` | `Array\u003cstring\u003e` | Yes | Routes that don't need authorization (public routes, e.g. login, registration and forgot password pages)\r\n`authService` | `new (...args: Array\u003cany\u003e) =\u003e any` | Yes | Service that will be used in your app\r\n`unauthenticatedRoute` | `string` | No | Route to redirect to after logout or when a user is not authenticated to view some page. By default it is set to `/login`\r\n`disableRedirectAfterUnauthorize` | `boolean` | No | Whether to redirect to `unauthenticatedRoute` after logout or when a user is not authenticated to view some page. By default it is set to `false`\r\n`authenticatedRoute` | `string` | No | Route to redirect after successful login\r\n`loginEndpoint` | `string` | No | Endpoint for login, e.g. `/api/token`\r\n`refreshTokenEndpoint` | `string` | No | Endpoint for refreshing token, e.g. `/api/token/refresh`\r\n`refreshTokenEndpointMethod` | `'get' \\| 'post'` | No | HTTP Method that will be used for calling endpoint to refresh token\r\n`isAuthenticatedField` | `string` | No | Field for cookie\r\n`rememberField` | `string` | No | Field for cookie\r\n`cookiesExpirationDays` | `number` | No | Expiration for authentication cookies when call authorize with remember flag set to true. By default it is set to 365\r\n\r\n#### AuthService\\\u003cUser extends AbstractUser\u003e\r\n\r\nStatic constant | Type\r\n--- | --- \r\n`DEFAULT_LOGIN_ENDPOINT` | `string`\r\n`DEFAULT_UNAUTHENTICATED_ROUTE` | `string`\r\n`DEFAULT_IS_AUTHENTICATED_FIELD` | `string`\r\n`DEFAULT_REFRESH_TOKEN_ENDPOINT` | `string`\r\n`DEFAULT_REMEMBER_FIELD` | `string`\r\n`DEFAULT_COOKIES_EXPIRATION_DAYS` | `number`\r\n\r\nField | Type\r\n--- | --- \r\n`isTokenRefreshing$` | `Observable\u003cboolean\u003e`\r\n`isAuthenticated$` | `Observable\u003cboolean\u003e`\r\n`cookiesExpiresDate` | `Date`\r\n\r\nMethod | Arguments | Return type\r\n--- | --- | --- \r\n`authorize\u003cT\u003e` | `credentials: AuthCredentials \u0026 T, remember: boolean` | `Observable\u003cAuthResponse\u003cUser\u003e\u003e` \r\n`manuallyAuthorize` | `authResponse: object, remember: boolean = true` | `Observable\u003cAuthResponse\u003cUser\u003e\u003e` \r\n`unauthorize` | | `void` \r\n`refreshToken` | | `Observable\u003cHttpResponse\u003cvoid\u003e\u003e` \r\n`setIsAuthenticated` | `remember: boolean` | `void`\r\n`resetIsAuthenticated` | | `void`\r\n`resetRemember` | | `void`\r\n\r\n#### AuthCredentials\r\n\r\nField | Type | Required\r\n--- | --- | ---\r\n`email` | `string` | No\r\n`password` | `string` | Yes\r\n\r\n#### AuthResponse\\\u003cUser extends AbstractUser\u003e\r\n\r\nField | Type | Required\r\n--- | --- | ---\r\n`user` | `User` | No\r\n\r\n### UserModule\r\n\r\n#### Config\r\n\r\n```ts\r\nUserModule.forRoot(config: UserConfig)\r\n```\r\n\r\n##### UserConfig\r\n\r\nName | Type | Required | Description\r\n--- | --- | --- | ---\r\n`userModel` | `new (user: any) =\u003e any` | Yes | Model (class) for user\r\n`userService` | `new (...args: Array\u003cany\u003e) =\u003e any` | Yes | Your UserService implementation\r\n`profileRelations` | `Array\u003cstring\u003e` | No | Relations for getting profile request. For example: `/profile?with[]=company\u0026with[]=clients`\r\n`profileRelationsKey` | `string` | No | `with` by default\r\n\r\n#### UserService\\\u003cUser extends AbstractUser\u003e\r\n\r\nField | Type\r\n--- | --- \r\n`profile$` | `Observable\u003cUser\u003e`\r\n\r\nMethod | Arguments | Return type\r\n--- | --- | --- \r\n`refreshProfile` | | `Observable\u003cUser\u003e` \r\n`loadProfile` | | `Observable\u003cUser\u003e` \r\n`updateProfile` | `user: User` | `Observable\u003cvoid\u003e` \r\n`updatePassword` | `userPasswords: UserPasswords` | `Observable\u003cvoid\u003e` \r\n`setProfile` | `user: User` | `void`\r\n`patchProfile` | `user: Partial\u003cUser\u003e` | `void`\r\n`resetRemember` | | `void`\r\n`resetProfile` | | `void`\r\n`userToPlain` | `user: User, options?: ClassTransformOptions` | `Object`\r\n`plainToUser` | `plain: object, options?: ClassTransformOptions` | `User` \r\n\r\n#### AbstractUser\r\n\r\nField | Type | Required\r\n--- | --- | ---\r\n`id` | `number \\| string` | Yes\r\n\r\n## Contributing\r\n\r\nContributions to Ronas IT Angular Common are welcome. The contribution guide can be found in the [Contributing guide](CONTRIBUTING.md).\r\n\r\n## License\r\n\r\nRonas IT Angular Common is open-sourced software licensed under the [MIT license](LICENSE).\r\n\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fronasit%2Fangular-common","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fronasit%2Fangular-common","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fronasit%2Fangular-common/lists"}