-
Notifications
You must be signed in to change notification settings - Fork 10
Add a package sdk-vanilla to the repository #176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # FusionAuth SDK for Vanilla JavaScript | ||
|
|
||
| This package provides a FusionAuth SDK for vanilla JavaScript with web components. It includes the following web components: | ||
|
|
||
| - `fa-account`: A button to redirect to the user's account management page. | ||
| - `fa-login`: A button component that will redirect the browser to the /app/login endpoint and start the OAuth flow. | ||
| - `fa-logout`: A button that will redirect the browser to the /app/logout endpoint. | ||
| - `fa-register`: A button that will redirect the browser to the /app/register endpoint. | ||
|
|
||
| ## Installation | ||
|
|
||
| To install the package, use npm or yarn: | ||
|
|
||
| ```bash | ||
| npm install @fusionauth/sdk-vanilla | ||
| ``` | ||
|
|
||
| or | ||
|
|
||
| ```bash | ||
| yarn add @fusionauth/sdk-vanilla | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Importing the Components | ||
|
|
||
| To use the web components in your project, import them as follows: | ||
|
|
||
| ```javascript | ||
| import { FaAccount, FaLogin, FaLogout, FaRegister } from '@fusionauth/sdk-vanilla'; | ||
| ``` | ||
|
|
||
| ### Using the Components | ||
|
|
||
| You can use the web components in your HTML as follows: | ||
|
|
||
| ```html | ||
| <fa-account></fa-account> | ||
| <fa-login></fa-login> | ||
| <fa-logout></fa-logout> | ||
| <fa-register></fa-register> | ||
| ``` | ||
|
|
||
| ### Configuring the FusionAuthService | ||
|
|
||
| To configure the `FusionAuthService`, use the `configure` method: | ||
|
|
||
| ```javascript | ||
| import { FusionAuthService } from '@fusionauth/sdk-vanilla'; | ||
|
|
||
| const fusionAuthService = FusionAuthService.configure({ | ||
| clientId: 'your-client-id', | ||
| redirectUri: 'your-redirect-uri', | ||
| serverUrl: 'your-server-url', | ||
| }); | ||
| ``` | ||
|
|
||
| ## Examples | ||
|
|
||
| Here is an example of how to use the `fa-login` component: | ||
|
|
||
| ```html | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <title>FusionAuth SDK Vanilla Example</title> | ||
| <script type="module"> | ||
| import { FaLogin } from '@fusionauth/sdk-vanilla'; | ||
|
|
||
| // Configure the FusionAuthService | ||
| const fusionAuthService = FusionAuthService.configure({ | ||
| clientId: 'your-client-id', | ||
| redirectUri: 'your-redirect-uri', | ||
| serverUrl: 'your-server-url', | ||
| }); | ||
| </script> | ||
| </head> | ||
| <body> | ||
| <fa-login></fa-login> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add all component buttons to this example |
||
| </body> | ||
| </html> | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| This package is licensed under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for more information. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| { | ||
| "name": "@fusionauth/sdk-vanilla", | ||
| "version": "0.1.0", | ||
| "description": "FusionAuth SDK for vanilla JavaScript with web components", | ||
| "author": "FusionAuth", | ||
| "license": "Apache", | ||
| "private": true, | ||
| "type": "module", | ||
| "main": "./dist/index.js", | ||
| "module": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "scripts": { | ||
| "build": "vite build", | ||
| "test": "vitest --watch=false", | ||
| "test:watch": "vitest", | ||
| "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0" | ||
| }, | ||
| "dependencies": { | ||
| "@fusionauth-sdk/core": "*" | ||
| }, | ||
| "devDependencies": { | ||
| "typescript": "^5.2.2", | ||
| "vite": "^5.2.0", | ||
| "vite-plugin-dts": "^3.8.0", | ||
| "vitest": "^1.4.0", | ||
| "eslint": "^8.32.0" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| import { describe, it, expect, beforeEach, afterEach } from 'vitest'; | ||
| import { FusionAuthService } from './FusionAuthService'; | ||
| import { SDKConfig } from '@fusionauth-sdk/core'; | ||
|
|
||
| describe('FusionAuthService', () => { | ||
| const config: SDKConfig = { | ||
| clientId: 'test-client-id', | ||
| redirectUri: 'http://localhost:3000', | ||
| serverUrl: 'http://localhost:9011', | ||
| }; | ||
|
|
||
| beforeEach(() => { | ||
| localStorage.clear(); | ||
|
Check failure on line 13 in packages/sdk-vanilla/src/FusionAuthService.test.ts
|
||
| }); | ||
|
|
||
| afterEach(() => { | ||
| localStorage.clear(); | ||
|
Check failure on line 17 in packages/sdk-vanilla/src/FusionAuthService.test.ts
|
||
| }); | ||
|
|
||
| it('should configure the FusionAuthService and store config in localStorage', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const storedConfig = localStorage.getItem('fusionauth-config'); | ||
| expect(storedConfig).toBe(JSON.stringify(config)); | ||
| expect(service).toBeInstanceOf(FusionAuthService); | ||
| }); | ||
|
|
||
| it('should retrieve the config from localStorage', () => { | ||
| localStorage.setItem('fusionauth-config', JSON.stringify(config)); | ||
| const retrievedConfig = FusionAuthService.getConfig(); | ||
| expect(retrievedConfig).toEqual(config); | ||
| }); | ||
|
|
||
| it('should throw an error if FusionAuthService is not configured', () => { | ||
| const service = new FusionAuthService(config); | ||
| localStorage.clear(); | ||
| expect(() => service.startLogin()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.startRegister()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.startLogout()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.manageAccount()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.fetchUserInfo()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.refreshToken()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.initAutoRefresh()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.handlePostRedirect()).toThrowError('FusionAuthService is not configured.'); | ||
| expect(() => service.isLoggedIn).toThrowError('FusionAuthService is not configured.'); | ||
| }); | ||
|
|
||
| it('should start login flow', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const startLoginSpy = vi.spyOn(service, 'startLogin'); | ||
| service.startLogin(); | ||
| expect(startLoginSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should start register flow', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const startRegisterSpy = vi.spyOn(service, 'startRegister'); | ||
| service.startRegister(); | ||
| expect(startRegisterSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should start logout flow', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const startLogoutSpy = vi.spyOn(service, 'startLogout'); | ||
| service.startLogout(); | ||
| expect(startLogoutSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should manage account', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const manageAccountSpy = vi.spyOn(service, 'manageAccount'); | ||
| service.manageAccount(); | ||
| expect(manageAccountSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should fetch user info', async () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const fetchUserInfoSpy = vi.spyOn(service, 'fetchUserInfo'); | ||
| await service.fetchUserInfo(); | ||
| expect(fetchUserInfoSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should refresh token', async () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const refreshTokenSpy = vi.spyOn(service, 'refreshToken'); | ||
| await service.refreshToken(); | ||
| expect(refreshTokenSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should initialize auto refresh', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const initAutoRefreshSpy = vi.spyOn(service, 'initAutoRefresh'); | ||
| service.initAutoRefresh(); | ||
| expect(initAutoRefreshSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should handle post redirect', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const handlePostRedirectSpy = vi.spyOn(service, 'handlePostRedirect'); | ||
| service.handlePostRedirect(); | ||
| expect(handlePostRedirectSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should return isLoggedIn status', () => { | ||
| const service = FusionAuthService.configure(config); | ||
| const isLoggedInSpy = vi.spyOn(service, 'isLoggedIn', 'get'); | ||
| const isLoggedIn = service.isLoggedIn; | ||
| expect(isLoggedInSpy).toHaveBeenCalled(); | ||
| expect(isLoggedIn).toBe(false); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| import { SDKCore, SDKConfig, UserInfo } from '@fusionauth-sdk/core'; | ||
|
|
||
| export class FusionAuthService { | ||
| private core: SDKCore; | ||
|
|
||
| constructor(config: SDKConfig) { | ||
| this.core = new SDKCore(config); | ||
| } | ||
|
|
||
| startLogin(state?: string): void { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| this.core.startLogin(state); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| startRegister(state?: string): void { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| this.core.startRegister(state); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| startLogout(): void { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| this.core.startLogout(); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| manageAccount(): void { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| this.core.manageAccount(); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| async fetchUserInfo<T = UserInfo>(): Promise<T> { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| return await this.core.fetchUserInfo<T>(); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| async refreshToken(): Promise<Response> { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| return await this.core.refreshToken(); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| initAutoRefresh(): NodeJS.Timeout | undefined { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| return this.core.initAutoRefresh(); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| handlePostRedirect(callback?: (state?: string) => void): void { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| this.core.handlePostRedirect(callback); | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| get isLoggedIn(): boolean { | ||
| const config = FusionAuthService.getConfig(); | ||
| if (config) { | ||
| this.core = new SDKCore(config); | ||
| return this.core.isLoggedIn; | ||
| } else { | ||
| throw new Error('FusionAuthService is not configured.'); | ||
| } | ||
| } | ||
|
|
||
| static configure(config: SDKConfig): FusionAuthService { | ||
| localStorage.setItem('fusionauth-config', JSON.stringify(config)); | ||
| return new FusionAuthService(config); | ||
| } | ||
|
|
||
| static getConfig(): SDKConfig | null { | ||
| const config = localStorage.getItem('fusionauth-config'); | ||
| return config ? JSON.parse(config) : null; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add all component buttons to this example