@visin/frontend-core 0.1.3 → 0.1.5

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.
@@ -1,8 +1,6 @@
1
1
  export interface ApiClientOptions {
2
2
  /** Read fresh at call time (app config may not be resolved yet at module load). */
3
3
  baseUrl: () => string;
4
- /** Reads the current auth token, e.g. `() => localStorage.getItem('authToken')`. */
5
- getToken?: () => string | null;
6
4
  /** Called on a 401 response, e.g. to redirect to the login page. */
7
5
  onUnauthorized?: () => void;
8
6
  }
@@ -16,14 +14,13 @@ export declare class ApiError extends Error {
16
14
  constructor(status: number, message: string, body?: unknown);
17
15
  }
18
16
  /**
19
- * Generic authenticated JSON fetch wrapper — base URL handling, Bearer-token
20
- * auth, structured errors, and an opt-in 401 → redirect-to-auth hook.
17
+ * Generic authenticated JSON fetch wrapper — base URL handling, structured
18
+ * errors, and an opt-in 401 → redirect-to-auth hook.
21
19
  *
22
- * Matches the auth transport all four Visin services actually use today
23
- * (a Bearer token read from `localStorage`, not a cookie), unlike a
24
- * cookie-based client would. Each front currently hand-rolls this
25
- * (`account-front/services/authService.ts`, `vision-front/config/visionApi.ts`)
26
- * with near-identical logic; new call sites can adopt this instead.
20
+ * Auth rides the shared `access_token` httpOnly cookie (COOKIE_DOMAIN is a
21
+ * shared parent domain across every Visin subdomain), so every request
22
+ * defaults to `credentials: 'include'` — callers can still override via
23
+ * `init.credentials` for the rare request that shouldn't send it.
27
24
  */
28
25
  export declare function createApiClient(options: ApiClientOptions): {
29
26
  request: <T = unknown>(path: string, init?: ApiRequestOptions) => Promise<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC/B,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,oJAAoJ;IACpJ,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;gBAEF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAM5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB;cAChC,CAAC,kBAAkB,MAAM,SAAQ,iBAAiB,KAAQ,OAAO,CAAC,CAAC,CAAC;UAoCnF,CAAC,kBAAkB,MAAM,SAAS,iBAAiB;WAClD,CAAC,kBAAkB,MAAM,SAAS,OAAO,SAAS,iBAAiB;UAEpE,CAAC,kBAAkB,MAAM,SAAS,OAAO,SAAS,iBAAiB;YAEjE,CAAC,kBAAkB,MAAM,SAAS,OAAO,SAAS,iBAAiB;aAElE,CAAC,kBAAkB,MAAM,SAAS,iBAAiB;EAE/D;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,oJAAoJ;IACpJ,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;gBAEF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAM5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB;cAChC,CAAC,kBAAkB,MAAM,SAAQ,iBAAiB,KAAQ,OAAO,CAAC,CAAC,CAAC;UAmCnF,CAAC,kBAAkB,MAAM,SAAS,iBAAiB;WAClD,CAAC,kBAAkB,MAAM,SAAS,OAAO,SAAS,iBAAiB;UAEpE,CAAC,kBAAkB,MAAM,SAAS,OAAO,SAAS,iBAAiB;YAEjE,CAAC,kBAAkB,MAAM,SAAS,OAAO,SAAS,iBAAiB;aAElE,CAAC,kBAAkB,MAAM,SAAS,iBAAiB;EAE/D;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
package/dist/apiClient.js CHANGED
@@ -7,24 +7,22 @@ export class ApiError extends Error {
7
7
  }
8
8
  }
9
9
  /**
10
- * Generic authenticated JSON fetch wrapper — base URL handling, Bearer-token
11
- * auth, structured errors, and an opt-in 401 → redirect-to-auth hook.
10
+ * Generic authenticated JSON fetch wrapper — base URL handling, structured
11
+ * errors, and an opt-in 401 → redirect-to-auth hook.
12
12
  *
13
- * Matches the auth transport all four Visin services actually use today
14
- * (a Bearer token read from `localStorage`, not a cookie), unlike a
15
- * cookie-based client would. Each front currently hand-rolls this
16
- * (`account-front/services/authService.ts`, `vision-front/config/visionApi.ts`)
17
- * with near-identical logic; new call sites can adopt this instead.
13
+ * Auth rides the shared `access_token` httpOnly cookie (COOKIE_DOMAIN is a
14
+ * shared parent domain across every Visin subdomain), so every request
15
+ * defaults to `credentials: 'include'` — callers can still override via
16
+ * `init.credentials` for the rare request that shouldn't send it.
18
17
  */
19
18
  export function createApiClient(options) {
20
19
  async function request(path, init = {}) {
21
20
  const { skipAuthRedirect, headers, ...rest } = init;
22
- const token = options.getToken?.();
23
21
  const response = await fetch(`${options.baseUrl()}${path}`, {
22
+ credentials: 'include',
24
23
  ...rest,
25
24
  headers: {
26
25
  'Content-Type': 'application/json',
27
- ...(token && { Authorization: `Bearer ${token}` }),
28
26
  ...headers
29
27
  }
30
28
  });
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAIjC,YAAY,MAAc,EAAE,OAAe,EAAE,IAAc;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,OAAyB;IACvD,KAAK,UAAU,OAAO,CAAc,IAAY,EAAE,OAA0B,EAAE;QAC5E,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;QAEpD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE;YAC1D,WAAW,EAAE,SAAS;YACtB,GAAG,IAAI;YACP,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,OAAO;aACX;SACF,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACjD,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,IAAa,CAAC;YAClB,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,8CAA8C;YAChD,CAAC;YACD,MAAM,OAAO,GAAI,IAAyC,EAAE,OAAO,IAAI,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CAAC;YAChH,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,SAAc,CAAC;QACxB,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,OAAO;QACL,OAAO;QACP,GAAG,EAAE,CAAc,IAAY,EAAE,IAAwB,EAAE,EAAE,CAAC,OAAO,CAAI,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAC1G,IAAI,EAAE,CAAc,IAAY,EAAE,IAAc,EAAE,IAAwB,EAAE,EAAE,CAC5E,OAAO,CAAI,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;QAC5G,GAAG,EAAE,CAAc,IAAY,EAAE,IAAc,EAAE,IAAwB,EAAE,EAAE,CAC3E,OAAO,CAAI,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;QAC3G,KAAK,EAAE,CAAc,IAAY,EAAE,IAAc,EAAE,IAAwB,EAAE,EAAE,CAC7E,OAAO,CAAI,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;QAC7G,MAAM,EAAE,CAAc,IAAY,EAAE,IAAwB,EAAE,EAAE,CAAC,OAAO,CAAI,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;KACjH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { AuthCheckResult, AuthService, AuthUser } from './authService';
3
+ export interface AuthContextValue {
4
+ user: AuthUser | null;
5
+ isAuthenticated: boolean;
6
+ isLoading: boolean;
7
+ /** Redirects to auth-front's login page, returning to the current page after. */
8
+ login: () => void;
9
+ logout: () => Promise<void>;
10
+ /** Re-runs the session check and updates the shared context state; returns the fresh result. */
11
+ refresh: () => Promise<AuthCheckResult>;
12
+ }
13
+ /**
14
+ * Builds a Context + `useAuth()` hook backed by a single `authService`
15
+ * instance, so every consumer in the app shares one session check instead
16
+ * of each component independently re-fetching `/auth/verify` on mount.
17
+ */
18
+ export declare function createAuthContext(authService: AuthService): {
19
+ AuthProvider: ({ children }: {
20
+ children: ReactNode;
21
+ }) => import("react").JSX.Element;
22
+ useAuth: () => AuthContextValue;
23
+ };
24
+ //# sourceMappingURL=AuthProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../../src/auth/AuthProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,iFAAiF;IACjF,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,gGAAgG;IAChG,OAAO,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;CACzC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,WAAW;iCAGpB;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE;mBAsCvC,gBAAgB;EASrC"}
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useState } from 'react';
3
+ /**
4
+ * Builds a Context + `useAuth()` hook backed by a single `authService`
5
+ * instance, so every consumer in the app shares one session check instead
6
+ * of each component independently re-fetching `/auth/verify` on mount.
7
+ */
8
+ export function createAuthContext(authService) {
9
+ const AuthContext = createContext(undefined);
10
+ function AuthProvider({ children }) {
11
+ const [user, setUser] = useState(null);
12
+ const [isLoading, setIsLoading] = useState(true);
13
+ const refresh = useCallback(async () => {
14
+ const result = await authService.checkAuth();
15
+ setUser(result.user);
16
+ return result;
17
+ }, []);
18
+ useEffect(() => {
19
+ let cancelled = false;
20
+ setIsLoading(true);
21
+ refresh().finally(() => {
22
+ if (!cancelled)
23
+ setIsLoading(false);
24
+ });
25
+ return () => {
26
+ cancelled = true;
27
+ };
28
+ }, [refresh]);
29
+ const login = useCallback(() => {
30
+ authService.redirectToLogin();
31
+ }, []);
32
+ const logout = useCallback(async () => {
33
+ await authService.logout();
34
+ setUser(null);
35
+ window.location.reload();
36
+ }, []);
37
+ return (_jsx(AuthContext.Provider, { value: { user, isAuthenticated: !!user, isLoading, login, logout, refresh }, children: children }));
38
+ }
39
+ function useAuth() {
40
+ const context = useContext(AuthContext);
41
+ if (context === undefined) {
42
+ throw new Error('useAuth must be used within an AuthProvider');
43
+ }
44
+ return context;
45
+ }
46
+ return { AuthProvider, useAuth };
47
+ }
48
+ //# sourceMappingURL=AuthProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthProvider.js","sourceRoot":"","sources":["../../src/auth/AuthProvider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAcpG;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAwB;IACxD,MAAM,WAAW,GAAG,aAAa,CAA+B,SAAS,CAAC,CAAC;IAE3E,SAAS,YAAY,CAAC,EAAE,QAAQ,EAA2B;QACzD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAkB,IAAI,CAAC,CAAC;QACxD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAA8B,EAAE;YAC/D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,CAAC;YAC7C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACrB,OAAO,MAAM,CAAC;QAChB,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,SAAS,CAAC,GAAG,EAAE;YACb,IAAI,SAAS,GAAG,KAAK,CAAC;YACtB,YAAY,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACrB,IAAI,CAAC,SAAS;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YACH,OAAO,GAAG,EAAE;gBACV,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC,CAAC;QACJ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAEd,MAAM,KAAK,GAAG,WAAW,CAAC,GAAS,EAAE;YACnC,WAAW,CAAC,eAAe,EAAE,CAAC;QAChC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;YACnD,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3B,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,OAAO,CACL,KAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAC9F,QAAQ,GACY,CACxB,CAAC;IACJ,CAAC;IAED,SAAS,OAAO;QACd,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Fields observed across the auth-service endpoints frontends call:
3
+ * `/auth/verify` always returns `groups` (JWT-derived); `/auth/profile`
4
+ * returns `firstName`/`lastName` (DB-derived) but not `groups`. Optional
5
+ * fields reflect which endpoint populated the result, not that the field
6
+ * is unreliable.
7
+ */
8
+ export interface AuthUser {
9
+ id: string;
10
+ email: string;
11
+ name: string;
12
+ picture?: string;
13
+ firstName?: string;
14
+ lastName?: string;
15
+ username?: string;
16
+ groups?: string[];
17
+ }
18
+ export interface AuthCheckResult {
19
+ authenticated: boolean;
20
+ user: AuthUser | null;
21
+ }
22
+ export interface AuthServiceOptions {
23
+ /** Base URL of auth-service, e.g. `() => getGlobalConfig().AUTH_SERVICE_URL`. */
24
+ authServiceUrl: () => string;
25
+ /** Base URL of the auth-front login page, e.g. `() => getGlobalConfig().AUTH_FRONT_URL`. */
26
+ authFrontUrl: () => string;
27
+ }
28
+ /**
29
+ * Session-management logic shared by every Visin frontend: `/auth/verify` +
30
+ * `/auth/profile` checks, logout, and the redirect to auth-front's login
31
+ * page. Auth rides the shared `access_token` httpOnly cookie (see
32
+ * `createApiClient`) rather than a token this service has to store itself.
33
+ * Each app previously hand-rolled this
34
+ * (`account-front/services/authService.ts`, `vision-front/contexts/AuthContext.tsx`)
35
+ * with near-identical but subtly diverging logic; wrap the result in
36
+ * `createAuthContext` for a React Context/hook, or use it directly for a
37
+ * plain-object service.
38
+ */
39
+ export declare function createAuthService({ authServiceUrl, authFrontUrl }: AuthServiceOptions): {
40
+ checkAuth: () => Promise<AuthCheckResult>;
41
+ getCurrentUser: () => Promise<AuthUser | null>;
42
+ getProfile: () => Promise<AuthUser | null>;
43
+ isAuthenticated: () => Promise<boolean>;
44
+ logout: () => Promise<boolean>;
45
+ redirectToLogin: (returnUrl?: string) => void;
46
+ };
47
+ export type AuthService = ReturnType<typeof createAuthService>;
48
+ //# sourceMappingURL=authService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../../src/auth/authService.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,4FAA4F;IAC5F,YAAY,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,kBAAkB;qBAS9D,OAAO,CAAC,eAAe,CAAC;0BA+Bb,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;sBAK5B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;2BAUnB,OAAO,CAAC,OAAO,CAAC;kBAKzB,OAAO,CAAC,OAAO,CAAC;kCAUJ,MAAM,KAAG,IAAI;EAMnD;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
@@ -0,0 +1,80 @@
1
+ import { createApiClient, ApiError } from '../apiClient';
2
+ /**
3
+ * Session-management logic shared by every Visin frontend: `/auth/verify` +
4
+ * `/auth/profile` checks, logout, and the redirect to auth-front's login
5
+ * page. Auth rides the shared `access_token` httpOnly cookie (see
6
+ * `createApiClient`) rather than a token this service has to store itself.
7
+ * Each app previously hand-rolled this
8
+ * (`account-front/services/authService.ts`, `vision-front/contexts/AuthContext.tsx`)
9
+ * with near-identical but subtly diverging logic; wrap the result in
10
+ * `createAuthContext` for a React Context/hook, or use it directly for a
11
+ * plain-object service.
12
+ */
13
+ export function createAuthService({ authServiceUrl, authFrontUrl }) {
14
+ const client = createApiClient({ baseUrl: authServiceUrl });
15
+ // Shared by concurrent callers (e.g. React StrictMode's double effect-invoke
16
+ // in development, or multiple components independently checking auth on
17
+ // first mount) so they trigger one /auth/verify request, not one each.
18
+ // Cleared once it settles, so the next distinct check gets a fresh request.
19
+ let inFlightCheck = null;
20
+ function checkAuth() {
21
+ if (inFlightCheck) {
22
+ return inFlightCheck;
23
+ }
24
+ inFlightCheck = (async () => {
25
+ try {
26
+ const data = await client.get('/auth/verify', { skipAuthRedirect: true });
27
+ if (data.success) {
28
+ return { authenticated: data.authenticated, user: data.user ?? null };
29
+ }
30
+ return { authenticated: false, user: null };
31
+ }
32
+ catch (error) {
33
+ // A 401 here just means "not logged in" — the normal state for an
34
+ // anonymous visitor, not a bug worth an error-level log.
35
+ if (!(error instanceof ApiError && error.status === 401)) {
36
+ console.error('Auth check failed:', error);
37
+ }
38
+ return { authenticated: false, user: null };
39
+ }
40
+ finally {
41
+ inFlightCheck = null;
42
+ }
43
+ })();
44
+ return inFlightCheck;
45
+ }
46
+ async function getCurrentUser() {
47
+ const result = await checkAuth();
48
+ return result.user;
49
+ }
50
+ async function getProfile() {
51
+ try {
52
+ const data = await client.get('/auth/profile');
53
+ return data.success ? (data.user ?? null) : null;
54
+ }
55
+ catch (error) {
56
+ console.error('Get profile failed:', error);
57
+ return null;
58
+ }
59
+ }
60
+ async function isAuthenticated() {
61
+ const result = await checkAuth();
62
+ return result.authenticated;
63
+ }
64
+ async function logout() {
65
+ try {
66
+ const data = await client.post('/auth/logout');
67
+ return data.success;
68
+ }
69
+ catch (error) {
70
+ console.error('Logout failed:', error);
71
+ return false;
72
+ }
73
+ }
74
+ function redirectToLogin(returnUrl) {
75
+ const currentUrl = returnUrl || window.location.href;
76
+ window.location.href = `${authFrontUrl()}?redirect_uri=${encodeURIComponent(currentUrl)}`;
77
+ }
78
+ return { checkAuth, getCurrentUser, getProfile, isAuthenticated, logout, redirectToLogin };
79
+ }
80
+ //# sourceMappingURL=authService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authService.js","sourceRoot":"","sources":["../../src/auth/authService.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorPage.d.ts","sourceRoot":"","sources":["../../../src/components/ErrorPage/ErrorPage.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,sDAAsD;IACtD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAA6B,EAC7B,OAMC,EACD,IAAsE,EACtE,SAAgB,EAChB,OAAwC,EACzC,EAAE,cAAc,+BA0BhB"}
1
+ {"version":3,"file":"ErrorPage.d.ts","sourceRoot":"","sources":["../../../src/components/ErrorPage/ErrorPage.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,sDAAsD;IACtD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAA6B,EAC7B,OAMC,EACD,IAAsE,EACtE,SAAgB,EAChB,OAAwC,EACzC,EAAE,cAAc,+BAkChB"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Typography, Button } from '@mui/material';
3
- import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
3
+ import ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';
4
4
  export function ErrorPage({ title = 'Configuration Error', message = (_jsxs(_Fragment, { children: ["Failed to load application configuration.", _jsx("br", {}), "Please check your network connection and try again."] })), icon = _jsx(ErrorOutlineIcon, { sx: { fontSize: 80, color: 'error.main' } }), showRetry = true, onRetry = () => window.location.reload() }) {
5
5
  return (_jsxs(Box, { sx: {
6
6
  display: 'flex',
@@ -9,6 +9,12 @@ export function ErrorPage({ title = 'Configuration Error', message = (_jsxs(_Fra
9
9
  justifyContent: 'center',
10
10
  height: '100vh',
11
11
  gap: 2
12
- }, children: [icon, _jsx(Typography, { variant: "h4", color: "error", fontWeight: 600, gutterBottom: true, children: title }), _jsx(Typography, { variant: "body1", color: "text.secondary", textAlign: "center", mb: showRetry ? 2 : 0, children: message }), showRetry && (_jsx(Button, { variant: "contained", color: "primary", onClick: onRetry, children: "Retry" }))] }));
12
+ }, children: [icon, _jsx(Typography, { variant: "h4", color: "error", gutterBottom: true, sx: {
13
+ fontWeight: 600
14
+ }, children: title }), _jsx(Typography, { variant: "body1", sx: {
15
+ color: "text.secondary",
16
+ textAlign: "center",
17
+ mb: showRetry ? 2 : 0
18
+ }, children: message }), showRetry && (_jsx(Button, { variant: "contained", color: "primary", onClick: onRetry, children: "Retry" }))] }));
13
19
  }
14
20
  //# sourceMappingURL=ErrorPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorPage.js","sourceRoot":"","sources":["../../../src/components/ErrorPage/ErrorPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,gBAAgB,MAAM,kCAAkC,CAAC;AAkBhE,MAAM,UAAU,SAAS,CAAC,EACxB,KAAK,GAAG,qBAAqB,EAC7B,OAAO,GAAG,CACR,2EAEE,cAAM,2DAEL,CACJ,EACD,IAAI,GAAG,KAAC,gBAAgB,IAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,GAAI,EACtE,SAAS,GAAG,IAAI,EAChB,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EACzB;IACf,OAAO,CACL,MAAC,GAAG,IACF,EAAE,EAAE;YACF,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,MAAM,EAAE,OAAO;YACf,GAAG,EAAE,CAAC;SACP,aAEA,IAAI,EACL,KAAC,UAAU,IAAC,OAAO,EAAC,IAAI,EAAC,KAAK,EAAC,OAAO,EAAC,UAAU,EAAE,GAAG,EAAE,YAAY,kBACjE,KAAK,GACK,EACb,KAAC,UAAU,IAAC,OAAO,EAAC,OAAO,EAAC,KAAK,EAAC,gBAAgB,EAAC,SAAS,EAAC,QAAQ,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YACxF,OAAO,GACG,EACZ,SAAS,IAAI,CACZ,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,KAAK,EAAC,SAAS,EAAC,OAAO,EAAE,OAAO,sBAEnD,CACV,IACG,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ErrorPage.js","sourceRoot":"","sources":["../../../src/components/ErrorPage/ErrorPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,gBAAgB,MAAM,mCAAmC,CAAC;AAkBjE,MAAM,UAAU,SAAS,CAAC,EACxB,KAAK,GAAG,qBAAqB,EAC7B,OAAO,GAAG,CACR,2EAEE,cAAM,2DAEL,CACJ,EACD,IAAI,GAAG,KAAC,gBAAgB,IAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,GAAI,EACtE,SAAS,GAAG,IAAI,EAChB,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EACzB;IACf,OAAO,CACL,MAAC,GAAG,IACF,EAAE,EAAE;YACF,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,MAAM,EAAE,OAAO;YACf,GAAG,EAAE,CAAC;SACP,aAEA,IAAI,EACL,KAAC,UAAU,IAAC,OAAO,EAAC,IAAI,EAAC,KAAK,EAAC,OAAO,EAAC,YAAY,QAAC,EAAE,EAAE;oBACtD,UAAU,EAAE,GAAG;iBAChB,YACE,KAAK,GACK,EACb,KAAC,UAAU,IACT,OAAO,EAAC,OAAO,EACf,EAAE,EAAE;oBACF,KAAK,EAAE,gBAAgB;oBACvB,SAAS,EAAE,QAAQ;oBACnB,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACtB,YACA,OAAO,GACG,EACZ,SAAS,IAAI,CACZ,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,KAAK,EAAC,SAAS,EAAC,OAAO,EAAE,OAAO,sBAEnD,CACV,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Loader.d.ts","sourceRoot":"","sources":["../../../src/components/Loader/Loader.tsx"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,MAAM,CAAC,EAAE,OAAsB,EAAE,IAAS,EAAE,UAAiB,EAAE,EAAE,WAAW,+BAmB3F"}
1
+ {"version":3,"file":"Loader.d.ts","sourceRoot":"","sources":["../../../src/components/Loader/Loader.tsx"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,MAAM,CAAC,EAAE,OAAsB,EAAE,IAAS,EAAE,UAAiB,EAAE,EAAE,WAAW,+BAqB3F"}
@@ -9,6 +9,8 @@ export function Loader({ message = 'Loading...', size = 48, fullHeight = true })
9
9
  height: fullHeight ? '100vh' : 'auto',
10
10
  gap: 2,
11
11
  py: fullHeight ? 0 : 8
12
- }, children: [_jsx(CircularProgress, { size: size }), _jsx(Typography, { variant: "body1", color: "text.secondary", children: message })] }));
12
+ }, children: [_jsx(CircularProgress, { size: size }), _jsx(Typography, { variant: "body1", sx: {
13
+ color: "text.secondary"
14
+ }, children: message })] }));
13
15
  }
14
16
  //# sourceMappingURL=Loader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Loader.js","sourceRoot":"","sources":["../../../src/components/Loader/Loader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAclE,MAAM,UAAU,MAAM,CAAC,EAAE,OAAO,GAAG,YAAY,EAAE,IAAI,GAAG,EAAE,EAAE,UAAU,GAAG,IAAI,EAAe;IAC1F,OAAO,CACL,MAAC,GAAG,IACF,EAAE,EAAE;YACF,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;YACrC,GAAG,EAAE,CAAC;YACN,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACvB,aAED,KAAC,gBAAgB,IAAC,IAAI,EAAE,IAAI,GAAI,EAChC,KAAC,UAAU,IAAC,OAAO,EAAC,OAAO,EAAC,KAAK,EAAC,gBAAgB,YAC/C,OAAO,GACG,IACT,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Loader.js","sourceRoot":"","sources":["../../../src/components/Loader/Loader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAclE,MAAM,UAAU,MAAM,CAAC,EAAE,OAAO,GAAG,YAAY,EAAE,IAAI,GAAG,EAAE,EAAE,UAAU,GAAG,IAAI,EAAe;IAC1F,OAAO,CACL,MAAC,GAAG,IACF,EAAE,EAAE;YACF,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;YACrC,GAAG,EAAE,CAAC;YACN,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACvB,aAED,KAAC,gBAAgB,IAAC,IAAI,EAAE,IAAI,GAAI,EAChC,KAAC,UAAU,IAAC,OAAO,EAAC,OAAO,EAAC,EAAE,EAAE;oBAC9B,KAAK,EAAE,gBAAgB;iBACxB,YACE,OAAO,GACG,IACT,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ import React, { ReactNode } from 'react';
2
+ export interface CreateConfigProviderOptions<T> {
3
+ /** Builds a config object from build-time env vars. Used in dev, during HMR fallback, and (with onFetchError: 'fallback') if /config.json fails to load in production. */
4
+ createDevConfig: () => T;
5
+ /** Whether the app is running in dev mode (pass `import.meta.env.DEV` from the calling app so Vite can statically replace it). */
6
+ isDev: boolean;
7
+ /** 'error-page' (default) renders ErrorPage if /config.json fails to load. 'fallback' falls back to createDevConfig() so the app can still render with build-time env vars. */
8
+ onFetchError?: 'error-page' | 'fallback';
9
+ /** Wraps the resolved config's children, e.g. with CssBaseline/ThemeProvider. Defaults to rendering children unwrapped. */
10
+ renderChildren?: (children: ReactNode) => ReactNode;
11
+ /** Rendered while config is loading. Defaults to the shared Loader. */
12
+ loadingFallback?: ReactNode;
13
+ }
14
+ export declare function createConfigProvider<T extends Record<string, any>>(options: CreateConfigProviderOptions<T>): {
15
+ ConfigProvider: ({ children }: {
16
+ children: ReactNode;
17
+ }) => React.JSX.Element;
18
+ ConfigContext: React.Context<T>;
19
+ useConfig: () => T;
20
+ getGlobalConfig: () => T;
21
+ };
22
+ //# sourceMappingURL=createConfigProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createConfigProvider.d.ts","sourceRoot":"","sources":["../../src/config/createConfigProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAkD,SAAS,EAAE,MAAM,OAAO,CAAC;AAIzF,MAAM,WAAW,2BAA2B,CAAC,CAAC;IAC5C,0KAA0K;IAC1K,eAAe,EAAE,MAAM,CAAC,CAAC;IACzB,kIAAkI;IAClI,KAAK,EAAE,OAAO,CAAC;IACf,+KAA+K;IAC/K,YAAY,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACzC,2HAA2H;IAC3H,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,SAAS,CAAC;IACpD,uEAAuE;IACvE,eAAe,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC;mCA8BnE;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE;;qBAJvC,CAAC;2BAbK,CAAC;EAsE9B"}
@@ -0,0 +1,70 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useState } from 'react';
3
+ import { Loader } from '../components/Loader';
4
+ import { ErrorPage } from '../components/ErrorPage';
5
+ export function createConfigProvider(options) {
6
+ const { createDevConfig, isDev, onFetchError = 'error-page', renderChildren = (children) => children, loadingFallback = _jsx(Loader, {}) } = options;
7
+ let globalConfig = null;
8
+ const ConfigContext = createContext({});
9
+ function getGlobalConfig() {
10
+ if (!globalConfig) {
11
+ if (isDev) {
12
+ // During HMR in development, config might be temporarily unavailable
13
+ const fallbackConfig = createDevConfig();
14
+ console.warn('Using fallback configuration during HMR:', fallbackConfig);
15
+ return fallbackConfig;
16
+ }
17
+ throw new Error('Configuration not initialized. Make sure ConfigProvider is mounted.');
18
+ }
19
+ return globalConfig;
20
+ }
21
+ function useConfig() {
22
+ return useContext(ConfigContext);
23
+ }
24
+ function ConfigProvider({ children }) {
25
+ const [config, setConfig] = useState(null);
26
+ const [error, setError] = useState(null);
27
+ useEffect(() => {
28
+ // In development, use environment variables directly
29
+ if (isDev) {
30
+ const devConfig = createDevConfig();
31
+ console.log('Using development configuration from environment variables:', devConfig);
32
+ setConfig(devConfig);
33
+ globalConfig = devConfig;
34
+ return;
35
+ }
36
+ // In production, fetch config.json
37
+ fetch('/config.json')
38
+ .then((res) => {
39
+ if (!res.ok)
40
+ throw new Error('Config fetch failed');
41
+ return res.json();
42
+ })
43
+ .then((loadedConfig) => {
44
+ console.log('Using production configuration from config.json:', loadedConfig);
45
+ setConfig(loadedConfig);
46
+ globalConfig = loadedConfig;
47
+ })
48
+ .catch((err) => {
49
+ console.error('Configuration load error:', err);
50
+ if (onFetchError === 'fallback') {
51
+ const fallback = createDevConfig();
52
+ setConfig(fallback);
53
+ globalConfig = fallback;
54
+ }
55
+ else {
56
+ setError(err.message);
57
+ }
58
+ });
59
+ }, []);
60
+ if (error) {
61
+ return _jsx(ErrorPage, {});
62
+ }
63
+ if (!config) {
64
+ return _jsx(_Fragment, { children: loadingFallback });
65
+ }
66
+ return (_jsx(ConfigContext.Provider, { value: config, children: renderChildren(children) }));
67
+ }
68
+ return { ConfigProvider, ConfigContext, useConfig, getGlobalConfig };
69
+ }
70
+ //# sourceMappingURL=createConfigProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createConfigProvider.js","sourceRoot":"","sources":["../../src/config/createConfigProvider.tsx"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,4 +4,10 @@ export { Loader } from './components/Loader';
4
4
  export type { LoaderProps } from './components/Loader';
5
5
  export { ErrorPage } from './components/ErrorPage';
6
6
  export type { ErrorPageProps } from './components/ErrorPage';
7
+ export { createAuthService } from './auth/authService';
8
+ export type { AuthService, AuthServiceOptions, AuthUser, AuthCheckResult } from './auth/authService';
9
+ export { createAuthContext } from './auth/AuthProvider';
10
+ export type { AuthContextValue } from './auth/AuthProvider';
11
+ export { createConfigProvider } from './config/createConfigProvider';
12
+ export type { CreateConfigProviderOptions } from './config/createConfigProvider';
7
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAElF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAElF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrG,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,YAAY,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC"}
package/dist/index.js CHANGED
@@ -2,9 +2,7 @@
2
2
  export { createApiClient, ApiError } from './apiClient';
3
3
  export { Loader } from './components/Loader';
4
4
  export { ErrorPage } from './components/ErrorPage';
5
- // Not yet extracted: account-front's `authService.ts`, auth-front's
6
- // `authFlow.ts`, and vision-front's `AuthContext.tsx` implement auth
7
- // (token storage, login/logout, session checks) three different ways
8
- // rather than as copies of one pattern, so unifying them needs its own
9
- // design pass across all three before landing here — see TODO.md.
5
+ export { createAuthService } from './auth/authService';
6
+ export { createAuthContext } from './auth/AuthProvider';
7
+ export { createConfigProvider } from './config/createConfigProvider';
10
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,oEAAoE;AACpE,qEAAqE;AACrE,qEAAqE;AACrE,uEAAuE;AACvE,kEAAkE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visin/frontend-core",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Shared frontend auth/API-client logic for Visin frontends",
5
5
  "author": "Toomas Tahves",
6
6
  "license": "MIT",
@@ -34,26 +34,26 @@
34
34
  "api-client"
35
35
  ],
36
36
  "peerDependencies": {
37
- "@mui/icons-material": "^7.3.11",
38
- "@mui/material": "^7.3.11",
37
+ "@mui/icons-material": "^9.2.0",
38
+ "@mui/material": "^9.2.0",
39
39
  "react": "^19.2.7"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@eslint/js": "^10.0.1",
43
- "@mui/icons-material": "^7.3.11",
44
- "@mui/material": "^7.3.11",
43
+ "@mui/icons-material": "^9.2.0",
44
+ "@mui/material": "^9.2.0",
45
45
  "@testing-library/jest-dom": "^6.6.3",
46
46
  "@testing-library/react": "^16.3.0",
47
- "@types/node": "^26.0.1",
47
+ "@types/node": "^26.1.0",
48
48
  "@types/react": "^19.2.17",
49
- "@vitest/coverage-v8": "^3.2.4",
49
+ "@vitest/coverage-v8": "^4.1.9",
50
50
  "eslint": "^10.6.0",
51
- "jsdom": "^26.1.0",
51
+ "jsdom": "^29.1.1",
52
52
  "react": "^19.2.7",
53
53
  "react-dom": "^19.2.7",
54
54
  "standard-version": "^9.5.0",
55
55
  "typescript": "^6.0.3",
56
56
  "typescript-eslint": "^8.62.1",
57
- "vitest": "^3.2.4"
57
+ "vitest": "^4.1.9"
58
58
  }
59
59
  }