{"version":3,"sources":["../../src/storage/useM2mAuth.tsx"],"sourcesContent":["import React, {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useState,\n} from \"react\";\nimport { LoginInput, requestLogin } from \"./api/login\";\nimport { checkJwtExpiration } from \"./jwt\";\nimport { m2mAuthTokenApi } from \"./client\";\nimport {\n  defaultStorageAdapter,\n  type PersistenceStorageAdapter,\n} from \"./persistenceDatabase\";\nimport { createRefreshAuth } from \"./refreshAuth\";\nimport { createClearAuth } from \"./clearAuth\";\n\nexport type { PersistenceStorageAdapter };\n\ninterface AuthenticationState {\n  token: string;\n  authenticated: boolean;\n  login: (input: LoginInput) => Promise<{ token?: string; error?: Error }>;\n  logout: () => void;\n  updateToken: (token: string) => Promise<{ error?: Error }>;\n  revalidating: boolean;\n  isLoginRequired: boolean;\n}\n\nconst AuthenticationContext = createContext<AuthenticationState | undefined>(\n  undefined,\n);\n\n/**\n * 認証状態を管理するProvider。\n * storageAdapterをカスタマイズする場合、参照が不変になるようにしてください。\n * 参照が変わるとトークン更新処理が再実行されます。\n */\nexport const M2mAuthenticationProvider = ({\n  children,\n  storageAdapter = defaultStorageAdapter,\n}: {\n  children: React.ReactNode;\n  storageAdapter?: PersistenceStorageAdapter;\n}) => {\n  const [token, setToken] = useState(m2mAuthTokenApi.getCache() ?? \"\");\n\n  const authenticated = useMemo(() => !!token, [token]);\n\n  const tryCheckAuth = useCallback(async () => {\n    const authToken = await m2mAuthTokenApi.get();\n    if (!(authToken !== null && checkJwtExpiration(authToken))) {\n      void m2mAuthTokenApi.clear();\n      setToken(\"\");\n    } else {\n      void m2mAuthTokenApi.set(authToken);\n      setToken(authToken);\n    }\n  }, []);\n\n  useEffect(() => {\n    // tryCheckAuthは依存配列が空のuseCallbackで定義されているため、\n    // 常に同じ関数参照を返し、このuseEffectは初回レンダリング後のみ実行される。\n    // レンダリング後に一度認証状態を確認する意図的な動作のため、このルールを無効化。\n    // eslint-disable-next-line react-hooks/set-state-in-effect\n    void tryCheckAuth();\n  }, [tryCheckAuth]);\n\n  const login = useCallback(\n    async (input: LoginInput) => {\n      const { data: auth, error } = await requestLogin(input);\n      if (auth) {\n        const authToken = auth.accessToken;\n\n        setToken(authToken);\n        await m2mAuthTokenApi.set(authToken);\n        await storageAdapter.set(auth);\n      }\n      return {\n        error,\n        token: auth ? auth.accessToken : undefined,\n      };\n    },\n    [storageAdapter],\n  );\n\n  const [revalidating, setRevalidating] = useState(true);\n\n  useEffect(() => {\n    const refreshAuth = createRefreshAuth(storageAdapter);\n    const callback = async () => {\n      const authToken = await refreshAuth();\n      if (authToken !== null) {\n        setToken(authToken);\n      }\n      setRevalidating(false);\n    };\n    void callback();\n    // Update auth every 3 hours\n    const timer = setInterval(callback, 3 * 60 * 60 * 1000);\n    return () => clearInterval(timer);\n  }, [storageAdapter]);\n\n  const logout = useCallback(async () => {\n    const clearAuth = createClearAuth(storageAdapter);\n    await clearAuth();\n    window.location.reload();\n  }, [storageAdapter]);\n\n  const updateToken = useCallback(async (token: string) => {\n    // checkJwtExpirationはトークンが有効(未失効)ならtrueを返す\n    const isTokenValid = checkJwtExpiration(token);\n    if (!isTokenValid) {\n      return {\n        error: new Error(\"M2MAuthToken is expired or invalid\"),\n      };\n    }\n    await m2mAuthTokenApi.set(token);\n    setToken(token);\n    return { error: undefined };\n  }, []);\n\n  const state = useMemo(() => {\n    return {\n      login,\n      logout,\n      token,\n      authenticated,\n      updateToken,\n      revalidating,\n      isLoginRequired: authenticated === false && revalidating === false,\n    } satisfies AuthenticationState;\n  }, [authenticated, login, logout, revalidating, token, updateToken]);\n  return (\n    <AuthenticationContext.Provider value={state}>\n      {children}\n    </AuthenticationContext.Provider>\n  );\n};\n\nexport const useAuth = () => {\n  const ctx = useContext(AuthenticationContext);\n  if (!ctx) {\n    throw new Error(\"AuthenticationProvider is not found\");\n  }\n  return ctx;\n};\n"],"mappings":"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","names":["token"]}