diff --git a/README.md b/README.md index f7179a5..8aab19e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@
-

lemon-web-core

+

LemonWebCore

- Shared library for LEMONCLOUD + LemonWebCore is a library designed for API requests and user authentication management in web-based projects for different cloud providers such as AWS, Azure, and GCP at LemonCloud.

@@ -18,33 +18,203 @@ --- -## Prerequisite +## Table of Contents -- [Node.js](https://nodejs.org/) -- [pnpm](https://pnpm.io/) +- [Installation](#installation) +- [Usage](#usage) + - [WebCoreFactory](#webcorefactory) + - [AWSWebCore](#awswebcore) + - [AzureWebCore](#azurewebcore) +- [API Reference](#api-reference) +- [Troubleshooting](#troubleshooting) -## Usage +## Installation -### Installation +You can install the LemonWebCore Library via npm: ```bash -$ git clone git@github.com:lemoncloud-io/lemon-web-core.git -$ cd lemon-web-core -$ pnpm install && pnpm prepare +npm install @lemoncloud/lemon-web-core ``` -## Running the app +## Usage + +The LemonWebCore Library allows you to create and use instances for different cloud providers. Below are the usage examples for WebCoreFactory, AWSWebCore, and AzureWebCore. -```bash -$ pnpm start +### WebCoreFactory + +The `WebCoreFactory` is used to create instances of `AWSWebCore` or `AzureWebCore` based on the cloud provider configuration. + +- AWSWebCore + +```typescript +import { WebCoreFactory, WebCoreConfig } from '@lemoncloud/lemon-web-core'; + +const config: WebCoreConfig<'aws'> = { + cloud: 'aws', + project: 'my-aws-project', + oAuthEndpoint: 'https://example.com/oauth', + region: 'us-west-2', +}; +const awsWebCore = WebCoreFactory.create(config); +await awsWebCore.init(); ``` -## Test +- AzureWebCore -```bash -$ pnpm test +```typescript +const azureConfig: WebCoreConfig<'azure'> = { + cloud: 'azure', + project: 'my-azure-project', + oAuthEndpoint: 'https://example.com/oauth', +}; + +const azureWebCore = WebCoreFactory.create(azureConfig); +await azureWebCore.init(); +``` + +### AWSWebCore + +The `AWSWebCore` class handles AWS-specific web core operations. Here is an example of how to use it: + +```typescript +import { AWSWebCore, WebCoreConfig } from '@lemoncloud/lemon-web-core'; + +const config: WebCoreConfig<'aws'> = { + cloud: 'aws', + project: 'my-aws-project', + oAuthEndpoint: 'https://example.com/oauth', + region: 'us-west-2', +}; + +const awsWebCore = new AWSWebCore(config); + +// Initialize +await awsWebCore.init(); + +// Make a signed request +const response = await awsWebCore.signedRequest('GET', 'https://example.com/api/resource'); +console.log(response.data); + +// Make a signed request with Builder +const example = await awsWebCore + .buildSignedRequest({ + method: 'GET', + baseURL: `https://api.lemoncloud.io/v1/oauth`, + }) + .setParams({ page: 0 }) + .setBody({ date: 'example' }) + .execute(); + +// Check authentication status +const isAuthenticated = await awsWebCore.isAuthenticated(); +console.log(isAuthenticated); +``` + +### AzureWebCore + +The `AzureWebCore` class handles Azure-specific web core operations. Here is an example of how to use it: + +```typescript +import { AzureWebCore, WebCoreConfig } from '@lemoncloud/lemon-web-core'; + +const config: WebCoreConfig<'azure'> = { + cloud: 'azure', + project: 'my-azure-project', + oAuthEndpoint: 'https://example.com/oauth', +}; + +const azureWebCore = new AzureWebCore(config); + +// Initialize +await azureWebCore.init(); + +// Make a signed request +const response = await azureWebCore.signedRequest('GET', 'https://example.com/api/resource'); +console.log(response.data); + +// Make a signed request with Builder +const example = await azureWebCore + .buildSignedRequest({ + method: 'GET', + baseURL: `https://api.lemoncloud.io/v1/oauth`, + }) + .setParams({ page: 0 }) + .setBody({ date: 'example' }) + .execute(); + +// Check authentication status +const isAuthenticated = await azureWebCore.isAuthenticated(); +console.log(isAuthenticated); ``` +## API Reference + +### WebCoreFactory + +- `create(config: WebCoreConfig): T` + +Creates an instance of `AWSWebCore` or `AzureWebCore` based on the provided cloud provider configuration. + +### AWSWebCore + +- `constructor(config: WebCoreConfig<'aws'>)` + +Creates an instance of `AWSWebCore` with the specified configuration. + +- `init(): Promise` + +Initializes the AWSWebCore instance. + +- `signedRequest(method: string, url: string, params?: Params, body?: Body, config?: AxiosRequestConfig): Promise>` + +Makes a signed HTTP request. + +- `isAuthenticated(): Promise` + +Checks if the user is authenticated. + +- `saveOAuthToken(token: LemonOAuthToken): Promise` + +Saves the OAuth token. + +- `logout(): Promise` + +Logs the user out by clearing the OAuth token. + +- `setUseXLemonIdentity(use: boolean): Promise` + +Sets whether to use the x-lemon-identity header. + +### AzureWebCore + +- `constructor(config: WebCoreConfig<'azure'>)` + +Creates an instance of `AzureWebCore` with the specified configuration. + +- `init(): Promise` + +Initializes the AzureWebCore instance. + +- `signedRequest(method: string, url: string, params?: Params, body?: Body, config?: AxiosRequestConfig): Promise>` + +Makes a signed HTTP request. + +- `isAuthenticated(): Promise` + +Checks if the user is authenticated. + +- `saveOAuthToken(token: LemonOAuthToken): Promise` + +Saves the OAuth token. + +- `logout(): Promise` + +Logs the user out by clearing the OAuth token. + +- `setUseXLemonIdentity(use: boolean): Promise` + +Sets whether to use the x-lemon-identity header. + ## Troubleshooting Please follow this guidelines when reporting bugs and feature requests: diff --git a/src/core/azure-web.core.ts b/src/core/azure-web.core.ts index a16f10f..bf47411 100644 --- a/src/core/azure-web.core.ts +++ b/src/core/azure-web.core.ts @@ -1,23 +1,138 @@ -import { WebCoreConfig, WebCoreService } from '../types'; +import { AzureWebCoreState, Body, LemonOAuthToken, Params, WebCoreConfig, WebCoreService } from '../types'; +import { AzureStorageService, USE_X_LEMON_IDENTITY_KEY } from '../token-storage'; +import { LoggerService } from '../utils'; +import { AxiosRequestConfig, AxiosResponse } from 'axios'; +import { AzureHttpRequestBuilder } from '../http'; -// TODO: implment Azure Core +/** + * Class to handle Azure-specific web core operations. + * Implements the WebCoreService interface. + */ export class AzureWebCore implements WebCoreService { - constructor(private readonly config: WebCoreConfig<'azure'>) {} - isAuthenticated(): Promise { - return Promise.resolve(false); + private readonly tokenStorage: AzureStorageService; + private readonly logger: LoggerService; + + /** + * Creates an instance of AzureWebCore. + * @param {WebCoreConfig<'azure'>} config - The configuration for the Azure web core. + */ + constructor(private readonly config: WebCoreConfig<'azure'>) { + this.logger = new LoggerService('AzureCore'); + this.logger.log('init AzureCore'); + this.tokenStorage = new AzureStorageService(this.config); } - logout(): Promise { - return; + /** + * Initializes the Azure web core by checking for cached tokens. + * @returns {Promise} - The state of the Azure web core after initialization. + */ + async init(): Promise { + this.logger.log('initialize AzureCore'); + const hasCachedToken = await this.tokenStorage.hasCachedToken(); + if (!hasCachedToken) { + this.logger.warn('has no token!'); + return 'no-token'; + } + + const shouldRefreshToken = await this.tokenStorage.shouldRefreshToken(); + if (shouldRefreshToken) { + this.logger.info('should refresh token!'); + // TODO: refresh azure token + } + return 'has-token'; + } + + /** + * Builds a signed request using the provided Axios configuration. + * @param {AxiosRequestConfig} config - The Axios request configuration. + * @returns {AzureHttpRequestBuilder} - The request builder for the signed request. + */ + buildSignedRequest(config: AxiosRequestConfig): AzureHttpRequestBuilder { + return new AzureHttpRequestBuilder(this.tokenStorage, config); + } + + /** + * Executes a signed HTTP request. + * @template T + * @param {string} method - The HTTP method to use for the request. + * @param {string} url - The URL for the request. + * @param {Params} [params={}] - The URL parameters for the request. + * @param {Body} [body] - The request body. + * @param {AxiosRequestConfig} [config] - Additional Axios request configuration. + * @returns {Promise>} - The Axios response. + */ + async signedRequest( + method: string, + url: string, + params: Params = {}, + body?: Body, + config?: AxiosRequestConfig + ): Promise> { + const builder = new AzureHttpRequestBuilder(this.tokenStorage, { + method, + baseURL: url, + params, + }); + if (body) { + builder.setBody(body); + } + if (config) { + builder.addAxiosRequestConfig(config); + } + return await builder.execute(); } - request(): Promise { - return Promise.resolve(undefined); + /** + * Retrieves all saved tokens from the storage. + * @returns {Promise<{ [key: string]: string }>} - An object containing all saved tokens. + */ + getSavedToken(): Promise<{ [key: string]: string }> { + return this.tokenStorage.getAllItems(); } - setUseXLemonIdentity(): void {} + /** + * Checks if the user is authenticated. + * @returns {Promise} - True if authenticated, otherwise false. + */ + async isAuthenticated(): Promise { + const hasCachedToken = await this.tokenStorage.hasCachedToken(); + if (!hasCachedToken) { + return false; + } + + const shouldRefreshToken = await this.tokenStorage.shouldRefreshToken(); + if (shouldRefreshToken) { + this.logger.info('should refresh token!'); + // TODO: refresh azure token + return true; + } + return true; + } + + /** + * Saves an OAuth token to the storage. + * @param {LemonOAuthToken} token - The OAuth token to save. + * @returns {Promise} - A promise that resolves when the token is saved. + */ + async saveOAuthToken(token: LemonOAuthToken): Promise { + return await this.tokenStorage.saveOAuthToken(token); + } + + /** + * Logs the user out by clearing the OAuth token from the storage. + * @returns {Promise} - A promise that resolves when the user is logged out. + */ + async logout(): Promise { + await this.tokenStorage.clearOAuthToken(); + return; + } - getSavedToken(): Promise<{ [p: string]: string }> { - return Promise.resolve({}); + /** + * Sets whether to use the x-lemon-identity header. + * @param {boolean} use - True to use the x-lemon-identity header, otherwise false. + * @returns {Promise} - A promise that resolves when the setting is updated. + */ + async setUseXLemonIdentity(use: boolean): Promise { + await this.tokenStorage.setItem(USE_X_LEMON_IDENTITY_KEY, `${use}`); } } diff --git a/src/types/lemon.ts b/src/types/lemon.ts index ff11eeb..3b3acc7 100644 --- a/src/types/lemon.ts +++ b/src/types/lemon.ts @@ -3,6 +3,11 @@ */ export type AWSWebCoreState = 'no-token' | 'refreshed' | 'build'; +/** + * Represents the state of the Azure Web Core service. + */ +export type AzureWebCoreState = 'no-token' | 'has-token'; + /** * Represents the ARN of a KMS key in AWS. */