valtech-components 2.0.997 → 2.0.998

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.
Files changed (30) hide show
  1. package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.component.mjs +385 -0
  2. package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.mjs +63 -0
  3. package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.component.mjs +313 -0
  4. package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.i18n.mjs +63 -0
  5. package/esm2022/lib/components/organisms/organization-view/organization-view.component.mjs +76 -1
  6. package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +5 -1
  7. package/esm2022/lib/services/apikeys/api-keys.service.mjs +46 -0
  8. package/esm2022/lib/services/apikeys/types.mjs +7 -0
  9. package/esm2022/lib/services/auth/auth.service.mjs +14 -1
  10. package/esm2022/lib/services/auth/types.mjs +1 -1
  11. package/esm2022/lib/services/org/org.service.mjs +8 -1
  12. package/esm2022/lib/services/org/types.mjs +1 -1
  13. package/esm2022/lib/version.mjs +2 -2
  14. package/esm2022/public-api.mjs +4 -1
  15. package/fesm2022/valtech-components.mjs +982 -42
  16. package/fesm2022/valtech-components.mjs.map +1 -1
  17. package/lib/components/organisms/api-keys-modal/api-keys-modal.component.d.ts +44 -0
  18. package/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.d.ts +6 -0
  19. package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +47 -0
  20. package/lib/components/organisms/member-import-modal/member-import-modal.i18n.d.ts +6 -0
  21. package/lib/components/organisms/organization-view/organization-view.component.d.ts +5 -0
  22. package/lib/services/apikeys/api-keys.service.d.ts +25 -0
  23. package/lib/services/apikeys/types.d.ts +46 -0
  24. package/lib/services/auth/auth.service.d.ts +7 -1
  25. package/lib/services/auth/types.d.ts +23 -0
  26. package/lib/services/org/org.service.d.ts +6 -1
  27. package/lib/services/org/types.d.ts +30 -0
  28. package/lib/version.d.ts +1 -1
  29. package/package.json +1 -1
  30. package/public-api.d.ts +5 -1
@@ -0,0 +1,44 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { ClientApiKey, ClientApiKeyWithSecret } from '../../../services/apikeys/types';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * `val-api-keys-modal` — gestión de Client API Keys org-scopeadas (ADR-023 fase 6).
6
+ *
7
+ * Lista las keys de la org, permite crear (mostrando el secreto UNA vez con copia)
8
+ * y revocar. Pensado para habilitar integraciones M2M del import de miembros, pero
9
+ * sirve a cualquier permiso del catálogo. Header canónico (Regla #5).
10
+ */
11
+ export declare class ApiKeysModalComponent implements OnInit {
12
+ private i18n;
13
+ private apiKeys;
14
+ /** Inyectado por `ModalService.open`. */
15
+ _modalRef?: {
16
+ dismiss: (data?: unknown, role?: string) => void;
17
+ };
18
+ /** Namespace i18n. */
19
+ i18nNamespace: string;
20
+ readonly keys: import("@angular/core").WritableSignal<ClientApiKey[]>;
21
+ readonly availablePermissions: import("@angular/core").WritableSignal<string[]>;
22
+ readonly loading: import("@angular/core").WritableSignal<boolean>;
23
+ readonly showCreate: import("@angular/core").WritableSignal<boolean>;
24
+ readonly submitting: import("@angular/core").WritableSignal<boolean>;
25
+ readonly errorMsg: import("@angular/core").WritableSignal<string>;
26
+ readonly secret: import("@angular/core").WritableSignal<ClientApiKeyWithSecret>;
27
+ readonly copied: import("@angular/core").WritableSignal<boolean>;
28
+ name: string;
29
+ expiresInDays: number | null;
30
+ readonly selectedPerms: import("@angular/core").WritableSignal<Set<string>>;
31
+ constructor();
32
+ ngOnInit(): void;
33
+ private refresh;
34
+ openCreate(): void;
35
+ togglePerm(perm: string, ev: Event): void;
36
+ submit(): void;
37
+ revoke(key: ClientApiKey): void;
38
+ copy(secret: string): Promise<void>;
39
+ finishSecret(): void;
40
+ dismiss(): void;
41
+ t(key: string): string;
42
+ static ɵfac: i0.ɵɵFactoryDeclaration<ApiKeysModalComponent, never>;
43
+ static ɵcmp: i0.ɵɵComponentDeclaration<ApiKeysModalComponent, "val-api-keys-modal", never, { "_modalRef": { "alias": "_modalRef"; "required": false; }; "i18nNamespace": { "alias": "i18nNamespace"; "required": false; }; }, {}, never, never, true, never>;
44
+ }
@@ -0,0 +1,6 @@
1
+ import { LanguagesContent } from '../../../services/i18n/types';
2
+ /**
3
+ * Defaults i18n (es/en) embebidos en `val-api-keys-modal` (ADR-023).
4
+ * Auto-registrados si el consumer no proveyó el namespace `Settings.ApiKeysModal`.
5
+ */
6
+ export declare const API_KEYS_MODAL_I18N: LanguagesContent;
@@ -0,0 +1,47 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { ImportMembersResponse, ImportOnConflict, ImportRowResult } from '../../../services/org/types';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * `val-member-import-modal` — panel de carga masiva de miembros (ADR-023 fase 6).
6
+ *
7
+ * El admin pega un CSV (`email,nombre,rol`); el modal lo parsea a filas y llama
8
+ * `OrgService.importMembers`. Muestra el resultado por-fila (partial success):
9
+ * `created` / `assigned` / `skipped` / `error`. Header canónico (Regla #5).
10
+ *
11
+ * Auto-registra defaults i18n (es/en) en `Settings.ImportModal`.
12
+ */
13
+ export declare class MemberImportModalComponent implements OnInit {
14
+ private i18n;
15
+ private orgService;
16
+ /** Org destino del import. */
17
+ orgId: string;
18
+ /** Nombres de roles disponibles (para el hint). Opcional. */
19
+ availableRoles: string[];
20
+ /** Callback tras una importación exitosa (≥1 fila procesada) — refresca la lista. */
21
+ onSuccess?: () => void;
22
+ /** Inyectado por `ModalService.open`. */
23
+ _modalRef?: {
24
+ dismiss: (data?: unknown, role?: string) => void;
25
+ };
26
+ /** Namespace i18n. */
27
+ i18nNamespace: string;
28
+ csv: string;
29
+ onConflict: ImportOnConflict;
30
+ sendActivation: boolean;
31
+ readonly submitting: import("@angular/core").WritableSignal<boolean>;
32
+ readonly errorMsg: import("@angular/core").WritableSignal<string>;
33
+ readonly results: import("@angular/core").WritableSignal<ImportMembersResponse>;
34
+ readonly rolesHint: import("@angular/core").Signal<string>;
35
+ readonly summaryLabel: import("@angular/core").Signal<string>;
36
+ constructor();
37
+ ngOnInit(): void;
38
+ /** Parsea el CSV pegado a filas {email,name,roleName}. Tolera header. */
39
+ private parseCsv;
40
+ submit(): void;
41
+ statusLabel(r: ImportRowResult): string;
42
+ reset(): void;
43
+ dismiss(): void;
44
+ t(key: string): string;
45
+ static ɵfac: i0.ɵɵFactoryDeclaration<MemberImportModalComponent, never>;
46
+ static ɵcmp: i0.ɵɵComponentDeclaration<MemberImportModalComponent, "val-member-import-modal", never, { "orgId": { "alias": "orgId"; "required": false; }; "availableRoles": { "alias": "availableRoles"; "required": false; }; "onSuccess": { "alias": "onSuccess"; "required": false; }; "_modalRef": { "alias": "_modalRef"; "required": false; }; "i18nNamespace": { "alias": "i18nNamespace"; "required": false; }; }, {}, never, never, true, never>;
47
+ }
@@ -0,0 +1,6 @@
1
+ import { LanguagesContent } from '../../../services/i18n/types';
2
+ /**
3
+ * Defaults i18n (es/en) embebidos en `val-member-import-modal` (ADR-023).
4
+ * Auto-registrados si el consumer no proveyó el namespace `Settings.ImportModal`.
5
+ */
6
+ export declare const MEMBER_IMPORT_MODAL_I18N: LanguagesContent;
@@ -61,6 +61,7 @@ export declare class OrganizationViewComponent {
61
61
  readonly members: import("@angular/core").WritableSignal<MemberDetail[]>;
62
62
  readonly membersLoading: import("@angular/core").WritableSignal<boolean>;
63
63
  private readonly membersLoadError;
64
+ readonly membersErrorState: import("@angular/core").Signal<EmptyStateMetadata>;
64
65
  readonly membersNextToken: import("@angular/core").WritableSignal<string>;
65
66
  readonly loadingMoreMembers: import("@angular/core").WritableSignal<boolean>;
66
67
  readonly showAllMembers: import("@angular/core").WritableSignal<boolean>;
@@ -81,12 +82,16 @@ export declare class OrganizationViewComponent {
81
82
  readonly viewPermissionsButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
82
83
  readonly transferButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
83
84
  readonly openInviteButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
85
+ readonly openImportButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
86
+ readonly openApiKeysButtonProps: import("@angular/core").Signal<Partial<ButtonMetadata>>;
84
87
  /** Guarda para detectar el primer disparo del effect (evita doble carga). */
85
88
  private lastLoadedOrgId;
86
89
  constructor();
87
90
  onEdit(): void;
88
91
  onLeave(): Promise<void>;
89
92
  onOpenInvite(): void;
93
+ onOpenImport(): void;
94
+ onOpenApiKeys(): void;
90
95
  onViewPermissions(): void;
91
96
  onOpenTransfer(): void;
92
97
  onTransfer(newOwnerId: string): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { Observable } from 'rxjs';
3
+ import { ValtechAuthConfig } from '../auth/types';
4
+ import { ClientApiKey, CreateApiKeyRequest, CreateApiKeyResponse, RevokeApiKeyResponse } from './types';
5
+ import * as i0 from "@angular/core";
6
+ /**
7
+ * Cliente HTTP de Client API Keys org-scopeadas (ADR-023). La org activa se
8
+ * resuelve en backend desde el JWT, así que el path no la incluye.
9
+ */
10
+ export declare class ApiKeyService {
11
+ private config;
12
+ private http;
13
+ constructor(config: ValtechAuthConfig, http: HttpClient);
14
+ private get baseUrl();
15
+ /** Lista las API keys de la org activa. */
16
+ list(): Observable<ClientApiKey[]>;
17
+ /** Crea una API key. La respuesta incluye el secreto (se muestra UNA vez). */
18
+ create(req: CreateApiKeyRequest): Observable<CreateApiKeyResponse>;
19
+ /** Revoca (elimina) una API key por id. */
20
+ revoke(keyId: string): Observable<RevokeApiKeyResponse>;
21
+ /** Catálogo de permisos asignables a una key. */
22
+ availablePermissions(): Observable<string[]>;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<ApiKeyService, never>;
24
+ static ɵprov: i0.ɵɵInjectableDeclaration<ApiKeyService>;
25
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Tipos de Client API Keys org-scopeadas (ADR-023). Contrato espejo de
3
+ * `lambdas/org` `/org/api-keys/*`. El orgID se resuelve del JWT (ActiveOrgID),
4
+ * no va en el path.
5
+ */
6
+ export interface ClientApiKey {
7
+ keyId: string;
8
+ name: string;
9
+ organizationId: string;
10
+ status: string;
11
+ permissions: string[];
12
+ rateLimit?: number;
13
+ expiresAt?: string;
14
+ allowedIps?: string[];
15
+ createdBy: string;
16
+ createdAt: string;
17
+ lastUsedAt?: string;
18
+ }
19
+ /** Solo en la respuesta de creación: el secreto se muestra UNA vez. */
20
+ export interface ClientApiKeyWithSecret extends ClientApiKey {
21
+ secret: string;
22
+ }
23
+ export interface CreateApiKeyRequest {
24
+ name: string;
25
+ permissions: string[];
26
+ rateLimit?: number;
27
+ expiresInDays?: number;
28
+ allowedIps?: string[];
29
+ }
30
+ export interface CreateApiKeyResponse {
31
+ operationId: string;
32
+ key: ClientApiKeyWithSecret;
33
+ }
34
+ export interface ListApiKeysResponse {
35
+ operationId: string;
36
+ keys: ClientApiKey[];
37
+ nextToken?: string;
38
+ }
39
+ export interface AvailablePermissionsResponse {
40
+ operationId: string;
41
+ permissions: string[];
42
+ }
43
+ export interface RevokeApiKeyResponse {
44
+ operationId: string;
45
+ message: string;
46
+ }
@@ -6,7 +6,7 @@ import { AuthStateService } from './auth-state.service';
6
6
  import { TokenService } from './token.service';
7
7
  import { AuthStorageService } from './storage.service';
8
8
  import { AuthSyncService } from './sync.service';
9
- import { SigninRequest, SigninResponse, SignupRequest, SignupResponse, VerifyEmailRequest, VerifyEmailResponse, ResendCodeRequest, ResendCodeResponse, MFAVerifyResponse, RefreshResponse, GetPermissionsResponse, GetProfileResponse, UpdateProfileRequest, UpdateProfileResponse, MFASetupResponse, MFAConfirmResponse, MFADisableRequest, MFADisableResponse, ForgotPasswordRequest, ForgotPasswordResponse, ResetPasswordRequest, ResetPasswordResponse, ChangePasswordResponse, DeleteAccountResponse, SendDeleteAccountCodeResponse, SwitchOrgResponse, MFAMethod, AuthError, ValtechAuthConfig, EnableNotificationsResult, NotificationPermissionState, RegisterDeviceResult, TOTPSetupResponse, TOTPVerifySetupResponse, TOTPDisableResponse, RegenerateBackupCodesResponse, BackupCodesCountResponse, OAuthProvider, LinkedProvider, HasPasswordResponse, UpdateHandleResponse, CheckHandleResponse, UpdateAvatarRequest, UpdateAvatarResponse, InitiateEmailChangeResponse, ConfirmEmailChangeStep1Response, ConfirmEmailChangeStep2Response } from './types';
9
+ import { SigninRequest, SigninResponse, SignupRequest, SignupResponse, VerifyEmailRequest, VerifyEmailResponse, ResendCodeRequest, ResendCodeResponse, MFAVerifyResponse, RefreshResponse, GetPermissionsResponse, GetProfileResponse, UpdateProfileRequest, UpdateProfileResponse, MFASetupResponse, MFAConfirmResponse, MFADisableRequest, MFADisableResponse, ForgotPasswordRequest, ForgotPasswordResponse, ResetPasswordRequest, ResetPasswordResponse, ActivateAccountRequest, ActivateAccountResponse, ChangePasswordResponse, DeleteAccountResponse, SendDeleteAccountCodeResponse, SwitchOrgResponse, MFAMethod, AuthError, ValtechAuthConfig, EnableNotificationsResult, NotificationPermissionState, RegisterDeviceResult, TOTPSetupResponse, TOTPVerifySetupResponse, TOTPDisableResponse, RegenerateBackupCodesResponse, BackupCodesCountResponse, OAuthProvider, LinkedProvider, HasPasswordResponse, UpdateHandleResponse, CheckHandleResponse, UpdateAvatarRequest, UpdateAvatarResponse, InitiateEmailChangeResponse, ConfirmEmailChangeStep1Response, ConfirmEmailChangeStep2Response } from './types';
10
10
  import { OAuthService } from './oauth.service';
11
11
  import { FirebaseService, MessagingService } from '../firebase';
12
12
  import { I18nService } from '../i18n';
@@ -288,6 +288,12 @@ export declare class AuthService implements OnDestroy {
288
288
  * Resetea la contraseña usando el código enviado por email.
289
289
  */
290
290
  resetPassword(request: ResetPasswordRequest): Observable<ResetPasswordResponse>;
291
+ /**
292
+ * Activa una cuenta pre-aprovisionada por una organización (ADR-023): define
293
+ * la contraseña con el token del enlace de email. En éxito el backend devuelve
294
+ * tokens de auto-signin → el usuario queda logueado (mismo flujo que verify-email).
295
+ */
296
+ activateAccount(request: ActivateAccountRequest): Observable<ActivateAccountResponse>;
291
297
  /**
292
298
  * Cambia la contraseña del usuario autenticado.
293
299
  * Requiere la contraseña actual para verificación.
@@ -238,6 +238,29 @@ export interface VerifyEmailResponse {
238
238
  expiresIn?: number;
239
239
  tokenType?: string;
240
240
  }
241
+ /**
242
+ * Request para activar una cuenta pre-aprovisionada por una organización
243
+ * (ADR-023): el usuario define su contraseña con el token del enlace de email.
244
+ */
245
+ export interface ActivateAccountRequest {
246
+ token: string;
247
+ newPassword: string;
248
+ }
249
+ /**
250
+ * Response de activación de cuenta. En éxito incluye tokens de auto-signin
251
+ * (mismo shape que verify-email) — el usuario queda logueado tras activar.
252
+ */
253
+ export interface ActivateAccountResponse {
254
+ operationId: string;
255
+ activated: boolean;
256
+ accessToken?: string;
257
+ refreshToken?: string;
258
+ firebaseToken?: string;
259
+ expiresIn?: number;
260
+ tokenType?: string;
261
+ roles?: string[];
262
+ permissions?: string[];
263
+ }
241
264
  /**
242
265
  * Request para reenviar código de verificación.
243
266
  */
@@ -1,7 +1,7 @@
1
1
  import { HttpClient } from '@angular/common/http';
2
2
  import { Observable } from 'rxjs';
3
3
  import { ValtechAuthConfig } from '../auth/types';
4
- import { Organization, ListMyOrgsResponse, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListOrgMembersResponse, OrgRole, ChangeMemberRoleResponse, PendingInvitation, AcceptInvitationResponse } from './types';
4
+ import { Organization, ListMyOrgsResponse, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListOrgMembersResponse, OrgRole, ChangeMemberRoleResponse, PendingInvitation, AcceptInvitationResponse, ImportMembersRequest, ImportMembersResponse } from './types';
5
5
  import * as i0 from "@angular/core";
6
6
  export declare class OrgService {
7
7
  private config;
@@ -21,6 +21,11 @@ export declare class OrgService {
21
21
  message: string;
22
22
  }>;
23
23
  inviteUser(orgId: string, req: InviteUserRequest): Observable<InviteUserResponse>;
24
+ /**
25
+ * Crea/asigna miembros en masa (ADR-023). Resultado por-fila (partial success):
26
+ * `created` (pre-aprovisionado), `assigned` (ya existía), `skipped`, `error`.
27
+ */
28
+ importMembers(orgId: string, req: ImportMembersRequest): Observable<ImportMembersResponse>;
24
29
  leaveOrg(orgId: string): Observable<LeaveOrgResponse>;
25
30
  getOrgMembers(orgId: string, params?: {
26
31
  limit?: number;
@@ -97,3 +97,33 @@ export interface ChangeMemberRoleResponse {
97
97
  orgId: string;
98
98
  roleId: string;
99
99
  }
100
+ export type ImportOnConflict = 'assignRole' | 'skip' | 'error';
101
+ export interface ImportUserRow {
102
+ email: string;
103
+ name?: string;
104
+ roleName: string;
105
+ }
106
+ export interface ImportMembersRequest {
107
+ users: ImportUserRow[];
108
+ onConflict?: ImportOnConflict;
109
+ sendActivation?: boolean;
110
+ }
111
+ export type ImportRowStatus = 'created' | 'assigned' | 'skipped' | 'error';
112
+ export interface ImportRowResult {
113
+ email: string;
114
+ status: ImportRowStatus;
115
+ userId?: string;
116
+ activation?: 'sent' | 'pending';
117
+ reason?: string;
118
+ }
119
+ export interface ImportSummary {
120
+ created: number;
121
+ assigned: number;
122
+ skipped: number;
123
+ failed: number;
124
+ }
125
+ export interface ImportMembersResponse {
126
+ operationId: string;
127
+ summary: ImportSummary;
128
+ results: ImportRowResult[];
129
+ }
package/lib/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Current version of valtech-components.
3
3
  * This is automatically updated during the publish process.
4
4
  */
5
- export declare const VERSION = "2.0.997";
5
+ export declare const VERSION = "2.0.998";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valtech-components",
3
- "version": "2.0.997",
3
+ "version": "2.0.998",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "valtech-firebase-config": "./src/lib/services/firebase/scripts/generate-sw-config.js"
package/public-api.d.ts CHANGED
@@ -301,6 +301,8 @@ export * from './lib/components/organisms/org-info-sheet/org-info-sheet.componen
301
301
  export * from './lib/components/organisms/invite-member-modal/invite-member-modal.component';
302
302
  export * from './lib/components/organisms/member-detail-modal/member-detail-modal.component';
303
303
  export * from './lib/components/organisms/member-detail-modal/types';
304
+ export * from './lib/components/organisms/member-import-modal/member-import-modal.component';
305
+ export * from './lib/components/organisms/api-keys-modal/api-keys-modal.component';
304
306
  export * from './lib/components/organisms/edit-org-modal/edit-org-modal.component';
305
307
  export * from './lib/components/organisms/transfer-ownership-modal/transfer-ownership-modal.component';
306
308
  export * from './lib/components/organisms/transfer-ownership-modal/types';
@@ -347,7 +349,9 @@ export * from './lib/services/legal-link/legal-link.service';
347
349
  export * from './lib/services/firebase';
348
350
  export * from './lib/services/auth';
349
351
  export { OrgService } from './lib/services/org/org.service';
350
- export type { Organization, OrgType, OrgPlan, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListMyOrgsResponse, OrgResponse, OrgMember, ListOrgMembersResponse, PendingInvitation, ListPendingInvitationsResponse, AcceptInvitationResponse, OrgRole, ListOrgRolesResponse, ChangeMemberRoleRequest, ChangeMemberRoleResponse, } from './lib/services/org/types';
352
+ export type { Organization, OrgType, OrgPlan, CreateOrgRequest, UpdateOrgRequest, InviteUserRequest, InviteUserResponse, LeaveOrgResponse, ListMyOrgsResponse, OrgResponse, OrgMember, ListOrgMembersResponse, PendingInvitation, ListPendingInvitationsResponse, AcceptInvitationResponse, OrgRole, ListOrgRolesResponse, ChangeMemberRoleRequest, ChangeMemberRoleResponse, ImportUserRow, ImportOnConflict, ImportMembersRequest, ImportRowStatus, ImportRowResult, ImportSummary, ImportMembersResponse, } from './lib/services/org/types';
353
+ export { ApiKeyService } from './lib/services/apikeys/api-keys.service';
354
+ export type { ClientApiKey, ClientApiKeyWithSecret, CreateApiKeyRequest, CreateApiKeyResponse, ListApiKeysResponse, AvailablePermissionsResponse, RevokeApiKeyResponse, } from './lib/services/apikeys/types';
351
355
  export * from './lib/services/i18n';
352
356
  export * from './lib/services/preferences';
353
357
  export * from './lib/services/network-status';