Transform more files to TS, replace lit-js-sdk with js-sdk (#4)
This commit is contained in:
parent
339986b666
commit
efb3eab092
15
package.json
15
package.json
@ -5,21 +5,24 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@lit-protocol/access-control-conditions": "2.1.17",
|
||||
"@lit-protocol/bls-sdk": "2.1.17",
|
||||
"@lit-protocol/constants": "2.1.17",
|
||||
"@lit-protocol/crypto": "2.1.17",
|
||||
"@lit-protocol/lit-node-client": "2.1.17",
|
||||
"@mui/material": "^5.10.16",
|
||||
"@react-oauth/google": "^0.4.0",
|
||||
"@simplewebauthn/browser": "^6.2.2",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "24.0.17",
|
||||
"@types/node": "12.6.9",
|
||||
"@types/react": "16.8.24",
|
||||
"@types/react-dom": "16.8.5",
|
||||
"@types/react-router-dom": "^4.3.4",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "^18.11.19",
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"base64url": "^3.0.1",
|
||||
"ethers": "^5.7.2",
|
||||
"js-base64": "^3.7.2",
|
||||
"lit-js-sdk": "^1.2.37",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
|
@ -1,40 +1,53 @@
|
||||
import * as LitJsSdk_accessControlConditions from "@lit-protocol/access-control-conditions";
|
||||
import * as LitJsSdk_blsSdk from "@lit-protocol/bls-sdk";
|
||||
import { AccsDefaultParams } from "@lit-protocol/constants";
|
||||
import * as LitJsSdk from "@lit-protocol/lit-node-client";
|
||||
import { Button, ButtonGroup } from "@mui/material";
|
||||
import { GoogleLogin } from "@react-oauth/google";
|
||||
import { ethers, utils } from "ethers";
|
||||
import LitJsSdk from "lit-js-sdk";
|
||||
import {
|
||||
startAuthentication,
|
||||
startRegistration,
|
||||
} from "@simplewebauthn/browser";
|
||||
import base64url from "base64url";
|
||||
import { utils } from "ethers";
|
||||
import { hexlify } from "ethers/lib/utils";
|
||||
import { useState } from "react";
|
||||
import "./App.css";
|
||||
import { ButtonGroup, Button } from "@mui/material";
|
||||
import base64url from "base64url";
|
||||
import {
|
||||
startRegistration,
|
||||
startAuthentication,
|
||||
} from "@simplewebauthn/browser";
|
||||
import { parseAuthenticatorData } from "./utils/parseAuthenticatorData";
|
||||
import { decodeAttestationObject } from "./utils/decodeAttestationObject";
|
||||
import { hexlify } from "ethers/lib/utils";
|
||||
import { parseAuthenticatorData } from "./utils/parseAuthenticatorData";
|
||||
|
||||
window.LitJsSdk = LitJsSdk;
|
||||
window.ethers = ethers;
|
||||
type CredentialResponse = any;
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
cbor: any;
|
||||
}
|
||||
}
|
||||
|
||||
const RELAY_API_URL =
|
||||
process.env.REACT_APP_RELAY_API_URL || "http://localhost:3001";
|
||||
|
||||
function App() {
|
||||
const [pkpEthAddress, setPkpEthAddress] = useState(null);
|
||||
const [googleCredentialResponse, setGoogleCredentialResponse] = useState(
|
||||
null
|
||||
);
|
||||
const [pkpPublicKey, setPkpPublicKey] = useState(null);
|
||||
const [pkpEthAddress, setPkpEthAddress] = useState<string>("");
|
||||
const [
|
||||
googleCredentialResponse,
|
||||
setGoogleCredentialResponse,
|
||||
] = useState<CredentialResponse | null>(null);
|
||||
const [pkpPublicKey, setPkpPublicKey] = useState<string>("");
|
||||
const [status, setStatus] = useState("");
|
||||
const [selectedAuthMethod, setSelectedAuthMethod] = useState(6);
|
||||
const [
|
||||
webAuthnCredentialPublicKey,
|
||||
setWebAuthnCredentialPublicKey,
|
||||
] = useState();
|
||||
const [webAuthnSignature, setWebAuthnSignature] = useState();
|
||||
const [webAuthnSignatureBase, setWebAuthnSignatureBase] = useState();
|
||||
] = useState<string>("");
|
||||
const [webAuthnSignature, setWebAuthnSignature] = useState<string>("");
|
||||
const [webAuthnSignatureBase, setWebAuthnSignatureBase] = useState<string>(
|
||||
""
|
||||
);
|
||||
|
||||
const handleLoggedInToGoogle = async credentialResponse => {
|
||||
const handleLoggedInToGoogle = async (
|
||||
credentialResponse: CredentialResponse
|
||||
) => {
|
||||
setStatus("Logged in to Google");
|
||||
console.log("Got response from google sign in: ", {
|
||||
credentialResponse,
|
||||
@ -98,8 +111,11 @@ function App() {
|
||||
<div>PKP Eth Address: {pkpEthAddress}</div>
|
||||
)}
|
||||
<h3>
|
||||
Step 2: Use Lit Network to obtain a session sig and then
|
||||
store an encryption condition.
|
||||
<s>
|
||||
Step 2: Use Lit Network to obtain a session sig and
|
||||
then store an encryption condition.
|
||||
</s>
|
||||
(Session Sigs do not work currently.)
|
||||
</h3>
|
||||
<button
|
||||
onClick={() =>
|
||||
@ -107,7 +123,11 @@ function App() {
|
||||
setStatus,
|
||||
selectedAuthMethod,
|
||||
googleCredentialResponse,
|
||||
{},
|
||||
{
|
||||
signature: "dummy",
|
||||
signatureBase: "dummy",
|
||||
credentialPublicKey: "dummy",
|
||||
},
|
||||
pkpEthAddress,
|
||||
pkpPublicKey
|
||||
)
|
||||
@ -153,7 +173,7 @@ function App() {
|
||||
// set in local state
|
||||
setWebAuthnCredentialPublicKey(
|
||||
hexlify(
|
||||
parsedAuthData.credentialPublicKey
|
||||
parsedAuthData.credentialPublicKey!
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -181,8 +201,11 @@ function App() {
|
||||
Authenticate
|
||||
</Button>
|
||||
<h3>
|
||||
Step 3: Use Lit Network to obtain a session sig and then
|
||||
store an encryption condition.
|
||||
<s>
|
||||
Step 3: Use Lit Network to obtain a session sig and
|
||||
then store an encryption condition.
|
||||
</s>
|
||||
(Session Sigs do not work currently.)
|
||||
</h3>
|
||||
<Button
|
||||
variant="contained"
|
||||
@ -212,8 +235,8 @@ function App() {
|
||||
export default App;
|
||||
|
||||
async function mintPkpUsingRelayerGoogleAuthVerificationEndpoint(
|
||||
credentialResponse,
|
||||
setStatusFn
|
||||
credentialResponse: any,
|
||||
setStatusFn: (status: string) => void
|
||||
) {
|
||||
setStatusFn("Minting PKP with relayer...");
|
||||
|
||||
@ -240,10 +263,10 @@ async function mintPkpUsingRelayerGoogleAuthVerificationEndpoint(
|
||||
}
|
||||
|
||||
async function mintPkpUsingRelayerWebAuthnVerificationEndpoint(
|
||||
signature,
|
||||
signatureBase,
|
||||
credentialPublicKey,
|
||||
setStatusFn
|
||||
signature: string,
|
||||
signatureBase: string,
|
||||
credentialPublicKey: string,
|
||||
setStatusFn: (status: string) => void
|
||||
) {
|
||||
setStatusFn("Minting PKP with relayer...");
|
||||
|
||||
@ -272,9 +295,15 @@ async function mintPkpUsingRelayerWebAuthnVerificationEndpoint(
|
||||
}
|
||||
|
||||
async function pollRequestUntilTerminalState(
|
||||
requestId,
|
||||
setStatusFn,
|
||||
onSuccess
|
||||
requestId: string,
|
||||
setStatusFn: (status: string) => void,
|
||||
onSuccess: ({
|
||||
pkpEthAddress,
|
||||
pkpPublicKey,
|
||||
}: {
|
||||
pkpEthAddress: string;
|
||||
pkpPublicKey: string;
|
||||
}) => void
|
||||
) {
|
||||
if (!requestId) {
|
||||
return;
|
||||
@ -326,15 +355,19 @@ async function pollRequestUntilTerminalState(
|
||||
}
|
||||
|
||||
async function handleStoreEncryptionCondition(
|
||||
setStatusFn,
|
||||
selectedAuthMethod,
|
||||
googleCredentialResponse,
|
||||
webAuthnVerificationMaterial,
|
||||
pkpEthAddress,
|
||||
pkpPublicKey
|
||||
setStatusFn: (status: string) => void,
|
||||
selectedAuthMethod: number,
|
||||
googleCredentialResponse: any,
|
||||
webAuthnVerificationMaterial: {
|
||||
signature: string;
|
||||
signatureBase: string;
|
||||
credentialPublicKey: string;
|
||||
},
|
||||
pkpEthAddress: string,
|
||||
pkpPublicKey: string
|
||||
) {
|
||||
setStatusFn("Storing encryption condition...");
|
||||
var unifiedAccessControlConditions = [
|
||||
var unifiedAccessControlConditions: AccsDefaultParams[] = [
|
||||
{
|
||||
conditionType: "evmBasic",
|
||||
contractAddress: "",
|
||||
@ -356,7 +389,7 @@ async function handleStoreEncryptionCondition(
|
||||
expiration,
|
||||
uri,
|
||||
litNodeClient,
|
||||
}) => {
|
||||
}: any) => {
|
||||
console.log("authNeededCallback fired");
|
||||
const authMethods =
|
||||
selectedAuthMethod === 6
|
||||
@ -396,9 +429,6 @@ async function handleStoreEncryptionCondition(
|
||||
expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours
|
||||
chain: "ethereum",
|
||||
resources: [`litEncryptionCondition://*`],
|
||||
sessionCapabilityObject: {
|
||||
def: ["litEncryptionCondition"],
|
||||
},
|
||||
switchChain: false,
|
||||
authNeededCallback,
|
||||
});
|
||||
@ -409,7 +439,7 @@ async function handleStoreEncryptionCondition(
|
||||
);
|
||||
|
||||
// value parameter - hash unified conditions
|
||||
const hashedAccessControlConditions = await LitJsSdk.hashUnifiedAccessControlConditions(
|
||||
const hashedAccessControlConditions = await LitJsSdk_accessControlConditions.hashUnifiedAccessControlConditions(
|
||||
unifiedAccessControlConditions
|
||||
);
|
||||
console.log("hashedAccessControlConditions", {
|
||||
@ -421,12 +451,12 @@ async function handleStoreEncryptionCondition(
|
||||
);
|
||||
|
||||
// key parameter - encrypt symmetric key then hash it
|
||||
const encryptedSymmetricKey = LitJsSdk.encryptWithBlsPubkey({
|
||||
pubkey: litNodeClient.networkPubKey,
|
||||
data: symmetricKey,
|
||||
});
|
||||
const hashedEncryptedSymmetricKeyStr = await LitJsSdk.hashEncryptionKey({
|
||||
encryptedSymmetricKey,
|
||||
const encryptedSymmetricKey = LitJsSdk_blsSdk.wasmBlsSdkHelpers.encrypt(
|
||||
LitJsSdk.uint8arrayFromString(litNodeClient.subnetPubKey, "base16"),
|
||||
symmetricKey
|
||||
);
|
||||
const hashedEncryptedSymmetricKeyStr = await hashBytes({
|
||||
bytes: new Uint8Array(encryptedSymmetricKey),
|
||||
});
|
||||
|
||||
// securityHash parameter - encrypt symmetric key, concat with creator address
|
||||
@ -435,9 +465,9 @@ async function handleStoreEncryptionCondition(
|
||||
...encryptedSymmetricKey,
|
||||
...pkpEthAddressBytes,
|
||||
]);
|
||||
// TODO: LitJsSdk.hashEncryptionKey ought to be renamed to just .hashBytes
|
||||
const securityHashStr = await LitJsSdk.hashEncryptionKey({
|
||||
encryptedSymmetricKey: securityHashPreimage,
|
||||
|
||||
const securityHashStr = await hashBytes({
|
||||
bytes: securityHashPreimage,
|
||||
});
|
||||
|
||||
console.log("Storing encryption condition with relay", {
|
||||
@ -476,102 +506,114 @@ async function handleStoreEncryptionCondition(
|
||||
}
|
||||
}
|
||||
|
||||
async function handleEncryptThenDecrypt(
|
||||
setStatusFn,
|
||||
googleCredentialResponse,
|
||||
pkpEthAddress,
|
||||
pkpPublicKey
|
||||
) {
|
||||
setStatusFn("Encrypting then decrypting...");
|
||||
var unifiedAccessControlConditions = [
|
||||
{
|
||||
conditionType: "evmBasic",
|
||||
contractAddress: "",
|
||||
standardContractType: "",
|
||||
chain: "mumbai",
|
||||
method: "",
|
||||
parameters: [":userAddress"],
|
||||
returnValueTest: {
|
||||
comparator: "=",
|
||||
value: pkpEthAddress,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// this will be fired if auth is needed. we can use this to prompt the user to sign in
|
||||
const authNeededCallback = async ({
|
||||
chain,
|
||||
resources,
|
||||
expiration,
|
||||
uri,
|
||||
litNodeClient,
|
||||
}) => {
|
||||
console.log("authNeededCallback fired");
|
||||
const sessionSig = await litNodeClient.signSessionKey({
|
||||
sessionKey: uri,
|
||||
authMethods: [
|
||||
{
|
||||
authMethodType: 6,
|
||||
accessToken: googleCredentialResponse.credential,
|
||||
},
|
||||
],
|
||||
pkpPublicKey,
|
||||
expiration,
|
||||
resources,
|
||||
chain,
|
||||
});
|
||||
console.log("got session sig from node and PKP: ", sessionSig);
|
||||
return sessionSig;
|
||||
};
|
||||
|
||||
// get the user a session with it
|
||||
const litNodeClient = new LitJsSdk.LitNodeClient({
|
||||
litNetwork: "serrano",
|
||||
});
|
||||
await litNodeClient.connect();
|
||||
|
||||
const sessionSigs = await litNodeClient.getSessionSigs({
|
||||
expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours
|
||||
chain: "ethereum",
|
||||
resources: [`litEncryptionCondition://*`],
|
||||
switchChain: false,
|
||||
authNeededCallback,
|
||||
});
|
||||
console.log("sessionSigs before saving encryption key: ", sessionSigs);
|
||||
|
||||
const { encryptedZip, symmetricKey } = await LitJsSdk.zipAndEncryptString(
|
||||
"this is a secret message"
|
||||
async function hashBytes({ bytes }: { bytes: Uint8Array }): Promise<string> {
|
||||
const hashOfBytes = await crypto.subtle.digest("SHA-256", bytes);
|
||||
const hashOfBytesStr = LitJsSdk.uint8arrayToString(
|
||||
new Uint8Array(hashOfBytes),
|
||||
"base16"
|
||||
);
|
||||
|
||||
const encryptedSymmetricKey = await litNodeClient.saveEncryptionKey({
|
||||
unifiedAccessControlConditions,
|
||||
symmetricKey,
|
||||
sessionSigs,
|
||||
});
|
||||
|
||||
const hashOfKey = await LitJsSdk.hashEncryptionKey({
|
||||
encryptedSymmetricKey,
|
||||
});
|
||||
|
||||
console.log("encrypted symmetric key", encryptedSymmetricKey);
|
||||
|
||||
const retrievedSymmKey = await litNodeClient.getEncryptionKey({
|
||||
unifiedAccessControlConditions,
|
||||
toDecrypt: LitJsSdk.uint8arrayToString(encryptedSymmetricKey, "base16"),
|
||||
sessionSigs,
|
||||
});
|
||||
|
||||
const decryptedFiles = await LitJsSdk.decryptZip(
|
||||
encryptedZip,
|
||||
retrievedSymmKey
|
||||
);
|
||||
const decryptedString = await decryptedFiles["string.txt"].async("text");
|
||||
console.log("decrypted string", decryptedString);
|
||||
|
||||
setStatusFn("Success!");
|
||||
return hashOfBytesStr;
|
||||
}
|
||||
|
||||
async function handleWebAuthnRegister(setStatusFn, onSuccess) {
|
||||
// async function handleEncryptThenDecrypt(
|
||||
// setStatusFn,
|
||||
// googleCredentialResponse,
|
||||
// pkpEthAddress,
|
||||
// pkpPublicKey
|
||||
// ) {
|
||||
// setStatusFn("Encrypting then decrypting...");
|
||||
// var unifiedAccessControlConditions = [
|
||||
// {
|
||||
// conditionType: "evmBasic",
|
||||
// contractAddress: "",
|
||||
// standardContractType: "",
|
||||
// chain: "mumbai",
|
||||
// method: "",
|
||||
// parameters: [":userAddress"],
|
||||
// returnValueTest: {
|
||||
// comparator: "=",
|
||||
// value: pkpEthAddress,
|
||||
// },
|
||||
// },
|
||||
// ];
|
||||
|
||||
// // this will be fired if auth is needed. we can use this to prompt the user to sign in
|
||||
// const authNeededCallback = async ({
|
||||
// chain,
|
||||
// resources,
|
||||
// expiration,
|
||||
// uri,
|
||||
// litNodeClient,
|
||||
// }) => {
|
||||
// console.log("authNeededCallback fired");
|
||||
// const sessionSig = await litNodeClient.signSessionKey({
|
||||
// sessionKey: uri,
|
||||
// authMethods: [
|
||||
// {
|
||||
// authMethodType: 6,
|
||||
// accessToken: googleCredentialResponse.credential,
|
||||
// },
|
||||
// ],
|
||||
// pkpPublicKey,
|
||||
// expiration,
|
||||
// resources,
|
||||
// chain,
|
||||
// });
|
||||
// console.log("got session sig from node and PKP: ", sessionSig);
|
||||
// return sessionSig;
|
||||
// };
|
||||
|
||||
// // get the user a session with it
|
||||
// const litNodeClient = new LitJsSdk.LitNodeClient({
|
||||
// litNetwork: "serrano",
|
||||
// });
|
||||
// await litNodeClient.connect();
|
||||
|
||||
// const sessionSigs = await litNodeClient.getSessionSigs({
|
||||
// expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours
|
||||
// chain: "ethereum",
|
||||
// resources: [`litEncryptionCondition://*`],
|
||||
// switchChain: false,
|
||||
// authNeededCallback,
|
||||
// });
|
||||
// console.log("sessionSigs before saving encryption key: ", sessionSigs);
|
||||
|
||||
// const { encryptedZip, symmetricKey } = await LitJsSdk.zipAndEncryptString(
|
||||
// "this is a secret message"
|
||||
// );
|
||||
|
||||
// const encryptedSymmetricKey = await litNodeClient.saveEncryptionKey({
|
||||
// unifiedAccessControlConditions,
|
||||
// symmetricKey,
|
||||
// sessionSigs,
|
||||
// });
|
||||
|
||||
// const hashOfKey = await LitJsSdk.hashEncryptionKey({
|
||||
// encryptedSymmetricKey,
|
||||
// });
|
||||
|
||||
// console.log("encrypted symmetric key", encryptedSymmetricKey);
|
||||
|
||||
// const retrievedSymmKey = await litNodeClient.getEncryptionKey({
|
||||
// unifiedAccessControlConditions,
|
||||
// toDecrypt: LitJsSdk.uint8arrayToString(encryptedSymmetricKey, "base16"),
|
||||
// sessionSigs,
|
||||
// });
|
||||
|
||||
// const decryptedFiles = await LitJsSdk.decryptZip(
|
||||
// encryptedZip,
|
||||
// retrievedSymmKey
|
||||
// );
|
||||
// const decryptedString = await decryptedFiles["string.txt"].async("text");
|
||||
// console.log("decrypted string", decryptedString);
|
||||
|
||||
// setStatusFn("Success!");
|
||||
// }
|
||||
|
||||
async function handleWebAuthnRegister(
|
||||
setStatusFn: (status: string) => void,
|
||||
onSuccess: ({ attResp }: { attResp: any }) => void
|
||||
) {
|
||||
const resp = await fetch(`${RELAY_API_URL}/generate-registration-options`);
|
||||
|
||||
let attResp;
|
||||
@ -620,11 +662,11 @@ async function handleWebAuthnRegister(setStatusFn, onSuccess) {
|
||||
}
|
||||
|
||||
async function handleWebAuthnAuthenticate(
|
||||
setStatusFn,
|
||||
webAuthnCredentialPublicKey,
|
||||
onSuccess,
|
||||
setWebAuthnSignatureFn,
|
||||
setWebAuthnSignatureBaseFn
|
||||
setStatusFn: (status: string) => void,
|
||||
webAuthnCredentialPublicKey: string,
|
||||
onSuccess: (resp: any) => void,
|
||||
setWebAuthnSignatureFn: (signature: string) => void,
|
||||
setWebAuthnSignatureBaseFn: (signatureBase: string) => void
|
||||
) {
|
||||
const resp = await fetch(
|
||||
`${RELAY_API_URL}/generate-authentication-options`
|
@ -5,7 +5,9 @@ import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import { GoogleOAuthProvider } from "@react-oauth/google";
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById("root") as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<GoogleOAuthProvider clientId="1071348522014-3qq1ln33ful535dnd8r4f6f9vtjrv2nu.apps.googleusercontent.com">
|
1
src/react-app-env.d.ts
vendored
Normal file
1
src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
@ -1,6 +1,8 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
import { ReportHandler } from "web-vitals";
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
@ -1,25 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"target": "es6",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
"src"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user