feat: prettier integration
This commit is contained in:
5
web/.prettierignore
Normal file
5
web/.prettierignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Ignore artifacts:
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
node_modules
|
||||||
|
public
|
1
web/.prettierrc
Normal file
1
web/.prettierrc
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
@ -24,31 +24,31 @@ export default tseslint.config({
|
|||||||
languageOptions: {
|
languageOptions: {
|
||||||
// other options...
|
// other options...
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
|
||||||
tsconfigRootDir: import.meta.dirname,
|
tsconfigRootDir: import.meta.dirname,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// eslint.config.js
|
// eslint.config.js
|
||||||
import reactX from 'eslint-plugin-react-x'
|
import reactX from "eslint-plugin-react-x";
|
||||||
import reactDom from 'eslint-plugin-react-dom'
|
import reactDom from "eslint-plugin-react-dom";
|
||||||
|
|
||||||
export default tseslint.config({
|
export default tseslint.config({
|
||||||
plugins: {
|
plugins: {
|
||||||
// Add the react-x and react-dom plugins
|
// Add the react-x and react-dom plugins
|
||||||
'react-x': reactX,
|
"react-x": reactX,
|
||||||
'react-dom': reactDom,
|
"react-dom": reactDom,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
// other rules...
|
// other rules...
|
||||||
// Enable its recommended typescript rules
|
// Enable its recommended typescript rules
|
||||||
...reactX.configs['recommended-typescript'].rules,
|
...reactX.configs["recommended-typescript"].rules,
|
||||||
...reactDom.configs.recommended.rules,
|
...reactDom.configs.recommended.rules,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
import js from '@eslint/js'
|
import js from "@eslint/js";
|
||||||
import globals from 'globals'
|
import globals from "globals";
|
||||||
import reactHooks from 'eslint-plugin-react-hooks'
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
import reactRefresh from "eslint-plugin-react-refresh";
|
||||||
import tseslint from 'typescript-eslint'
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
export default tseslint.config(
|
export default tseslint.config(
|
||||||
{ ignores: ['dist'] },
|
{ ignores: ["dist"] },
|
||||||
{
|
{
|
||||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||||
files: ['**/*.{ts,tsx}'],
|
files: ["**/*.{ts,tsx}"],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
ecmaVersion: 2020,
|
ecmaVersion: 2020,
|
||||||
globals: globals.browser,
|
globals: globals.browser,
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
'react-hooks': reactHooks,
|
"react-hooks": reactHooks,
|
||||||
'react-refresh': reactRefresh,
|
"react-refresh": reactRefresh,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
...reactHooks.configs.recommended.rules,
|
...reactHooks.configs.recommended.rules,
|
||||||
'react-refresh/only-export-components': [
|
"react-refresh/only-export-components": [
|
||||||
'warn',
|
"warn",
|
||||||
{ allowConstantExport: true },
|
{ allowConstantExport: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
17
web/package-lock.json
generated
17
web/package-lock.json
generated
@ -34,6 +34,7 @@
|
|||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
|
"prettier": "3.5.3",
|
||||||
"sass": "^1.89.0",
|
"sass": "^1.89.0",
|
||||||
"typescript": "~5.8.3",
|
"typescript": "~5.8.3",
|
||||||
"typescript-eslint": "^8.30.1",
|
"typescript-eslint": "^8.30.1",
|
||||||
@ -4262,6 +4263,22 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||||
|
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/process": {
|
"node_modules/process": {
|
||||||
"version": "0.11.10",
|
"version": "0.11.10",
|
||||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
|
"prettier": "3.5.3",
|
||||||
"sass": "^1.89.0",
|
"sass": "^1.89.0",
|
||||||
"typescript": "~5.8.3",
|
"typescript": "~5.8.3",
|
||||||
"typescript-eslint": "^8.30.1",
|
"typescript-eslint": "^8.30.1",
|
||||||
|
@ -13,7 +13,7 @@ export const codeApi = async (accessToken: string, nonce: string) => {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${accessToken}`,
|
Authorization: `Bearer ${accessToken}`,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.status !== 200 && response.status !== 201)
|
if (response.status !== 200 && response.status !== 201)
|
||||||
|
@ -28,7 +28,7 @@ const processRefreshQueue = async (token: string | null) => {
|
|||||||
|
|
||||||
const refreshToken = async (
|
const refreshToken = async (
|
||||||
accountId: string,
|
accountId: string,
|
||||||
refreshToken: string
|
refreshToken: string,
|
||||||
): Promise<{ access: string; refresh: string }> => {
|
): Promise<{ access: string; refresh: string }> => {
|
||||||
const db = useDbStore.getState().db;
|
const db = useDbStore.getState().db;
|
||||||
const loadAccounts = useAuth.getState().loadAccounts;
|
const loadAccounts = useAuth.getState().loadAccounts;
|
||||||
@ -79,7 +79,7 @@ axios.interceptors.request.use(
|
|||||||
try {
|
try {
|
||||||
const { access } = await refreshToken(
|
const { access } = await refreshToken(
|
||||||
account!.accountId,
|
account!.accountId,
|
||||||
account!.refresh
|
account!.refresh,
|
||||||
);
|
);
|
||||||
token = access;
|
token = access;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -97,7 +97,7 @@ axios.interceptors.request.use(
|
|||||||
request.headers["Authorization"] = `Bearer ${token}`;
|
request.headers["Authorization"] = `Bearer ${token}`;
|
||||||
return request;
|
return request;
|
||||||
},
|
},
|
||||||
(error) => Promise.reject(error)
|
(error) => Promise.reject(error),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const handleApiError = async (response: AxiosResponse) => {
|
export const handleApiError = async (response: AxiosResponse) => {
|
||||||
|
@ -15,7 +15,7 @@ export const refreshTokenApi = async (refreshToken: string) => {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${refreshToken}`,
|
Authorization: `Bearer ${refreshToken}`,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.status !== 200 && response.status !== 201)
|
if (response.status !== 200 && response.status !== 201)
|
||||||
|
@ -29,7 +29,7 @@ export const OAuthProvider: FC<IOAuthProvider> = ({ children }) => {
|
|||||||
window.location.replace(`${redirectURI}?${params.toString()}`);
|
window.location.replace(`${redirectURI}?${params.toString()}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[active, nonce, redirectURI, state]
|
[active, nonce, redirectURI, state],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -14,7 +14,7 @@ const AccountList: FC = () => {
|
|||||||
(account: LocalAccount) => {
|
(account: LocalAccount) => {
|
||||||
updateActiveAccount(account);
|
updateActiveAccount(account);
|
||||||
},
|
},
|
||||||
[updateActiveAccount]
|
[updateActiveAccount],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -73,7 +73,7 @@ const AuthLayout = () => {
|
|||||||
if (!active) {
|
if (!active) {
|
||||||
console.log(
|
console.log(
|
||||||
"setting search params:",
|
"setting search params:",
|
||||||
Object.fromEntries(searchParams.entries())
|
Object.fromEntries(searchParams.entries()),
|
||||||
);
|
);
|
||||||
setActive(true);
|
setActive(true);
|
||||||
setClientID(searchParams.get("client_id") ?? "");
|
setClientID(searchParams.get("client_id") ?? "");
|
||||||
|
@ -9,5 +9,5 @@ const root = document.getElementById("root")!;
|
|||||||
createRoot(root).render(
|
createRoot(root).render(
|
||||||
<OAuthProvider>
|
<OAuthProvider>
|
||||||
<App />
|
<App />
|
||||||
</OAuthProvider>
|
</OAuthProvider>,
|
||||||
);
|
);
|
||||||
|
@ -67,13 +67,13 @@ export default function LoginPage() {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
setError(
|
setError(
|
||||||
"Failed to create account. " +
|
"Failed to create account. " +
|
||||||
(err.message ?? "Unexpected error happened")
|
(err.message ?? "Unexpected error happened"),
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[repo, reset, updateActiveAccount]
|
[repo, reset, updateActiveAccount],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -56,11 +56,11 @@ export default function RegisterPage() {
|
|||||||
setError(
|
setError(
|
||||||
`Failed to create an account. ${
|
`Failed to create an account. ${
|
||||||
text[0].toUpperCase() + text.slice(1)
|
text[0].toUpperCase() + text.slice(1)
|
||||||
}`
|
}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setSuccess(
|
setSuccess(
|
||||||
"Account has been created. You can now log into your new account"
|
"Account has been created. You can now log into your new account",
|
||||||
);
|
);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ export default function RegisterPage() {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[reset]
|
[reset],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -61,7 +61,7 @@ export const encryptToken = async (token: string) => {
|
|||||||
const cipherText = await crypto.subtle.encrypt(
|
const cipherText = await crypto.subtle.encrypt(
|
||||||
{ name: "AES-GCM", iv },
|
{ name: "AES-GCM", iv },
|
||||||
deviceKey,
|
deviceKey,
|
||||||
encoder.encode(token)
|
encoder.encode(token),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -84,7 +84,7 @@ export const decryptToken = async (encrypted: {
|
|||||||
iv: new Uint8Array(encrypted.iv),
|
iv: new Uint8Array(encrypted.iv),
|
||||||
},
|
},
|
||||||
deviceKey,
|
deviceKey,
|
||||||
new Uint8Array(encrypted.data)
|
new Uint8Array(encrypted.data),
|
||||||
);
|
);
|
||||||
|
|
||||||
return decoder.decode(decrypted);
|
return decoder.decode(decrypted);
|
||||||
@ -92,7 +92,7 @@ export const decryptToken = async (encrypted: {
|
|||||||
|
|
||||||
export const saveAccount = async (
|
export const saveAccount = async (
|
||||||
db: IDBPDatabase,
|
db: IDBPDatabase,
|
||||||
req: CreateAccountRequest
|
req: CreateAccountRequest,
|
||||||
): Promise<LocalAccount> => {
|
): Promise<LocalAccount> => {
|
||||||
const access = await encryptToken(req.access);
|
const access = await encryptToken(req.access);
|
||||||
const refresh = await encryptToken(req.refresh);
|
const refresh = await encryptToken(req.refresh);
|
||||||
@ -141,7 +141,7 @@ export const getAllAccounts = async (db: IDBPDatabase) => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(`Failed to decrypt account ${account.label}:`, err);
|
console.warn(`Failed to decrypt account ${account.label}:`, err);
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
).filter((acc) => acc !== undefined);
|
).filter((acc) => acc !== undefined);
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ export const getAccountRaw = async (db: IDBPDatabase, accountId: string) => {
|
|||||||
|
|
||||||
export const updateAccountTokens = async (
|
export const updateAccountTokens = async (
|
||||||
db: IDBPDatabase,
|
db: IDBPDatabase,
|
||||||
req: UpdateAccountTokensRequest
|
req: UpdateAccountTokensRequest,
|
||||||
) => {
|
) => {
|
||||||
const account = await getAccountRaw(db, req.accountId);
|
const account = await getAccountRaw(db, req.accountId);
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ export const updateAccountTokens = async (
|
|||||||
|
|
||||||
export const updateAccountInfo = async (
|
export const updateAccountInfo = async (
|
||||||
db: IDBPDatabase,
|
db: IDBPDatabase,
|
||||||
req: UpdateAccountInfoRequest
|
req: UpdateAccountInfoRequest,
|
||||||
) => {
|
) => {
|
||||||
const account = await getAccountRaw(db, req.accountId);
|
const account = await getAccountRaw(db, req.accountId);
|
||||||
await db?.put?.("accounts", {
|
await db?.put?.("accounts", {
|
||||||
@ -229,7 +229,7 @@ export const useAccountRepo = () => {
|
|||||||
|
|
||||||
return saveAccount(db, req);
|
return saveAccount(db, req);
|
||||||
},
|
},
|
||||||
[db]
|
[db],
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadAll = useCallback(async () => {
|
const loadAll = useCallback(async () => {
|
||||||
@ -244,7 +244,7 @@ export const useAccountRepo = () => {
|
|||||||
|
|
||||||
return getAccount(db, accountId);
|
return getAccount(db, accountId);
|
||||||
},
|
},
|
||||||
[db]
|
[db],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { save, loadAll, getOne };
|
return { save, loadAll, getOne };
|
||||||
|
@ -37,7 +37,7 @@ export const deriveDeviceKey = async (deviceKeyId: string) => {
|
|||||||
encoder.encode(deviceKeyId),
|
encoder.encode(deviceKeyId),
|
||||||
{ name: "PBKDF2" },
|
{ name: "PBKDF2" },
|
||||||
false,
|
false,
|
||||||
["deriveKey"]
|
["deriveKey"],
|
||||||
);
|
);
|
||||||
return crypto.subtle.deriveKey(
|
return crypto.subtle.deriveKey(
|
||||||
{
|
{
|
||||||
@ -49,6 +49,6 @@ export const deriveDeviceKey = async (deviceKeyId: string) => {
|
|||||||
baseKey,
|
baseKey,
|
||||||
{ name: "AES-GCM", length: 256 },
|
{ name: "AES-GCM", length: 256 },
|
||||||
false,
|
false,
|
||||||
["encrypt", "decrypt"]
|
["encrypt", "decrypt"],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -5,14 +5,14 @@ export type EncryptedToken = {
|
|||||||
|
|
||||||
export const encryptToken = async (
|
export const encryptToken = async (
|
||||||
token: string,
|
token: string,
|
||||||
key: CryptoKey
|
key: CryptoKey,
|
||||||
): Promise<EncryptedToken> => {
|
): Promise<EncryptedToken> => {
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
const iv = crypto.getRandomValues(new Uint8Array(12));
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||||
const cipherText = await crypto.subtle.encrypt(
|
const cipherText = await crypto.subtle.encrypt(
|
||||||
{ name: "AES-GCM", iv },
|
{ name: "AES-GCM", iv },
|
||||||
key,
|
key,
|
||||||
encoder.encode(token)
|
encoder.encode(token),
|
||||||
);
|
);
|
||||||
return { cipherText, iv };
|
return { cipherText, iv };
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user