diff --git a/.env.example b/.env.example index e6f14f0..3273c9a 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ NEXTAUTH_SECRET="1234" GITHUB_SECRET="" GITHUB_ID="" NEXT_PUBLIC_COMPILE_API_ENDPOINT="http://localhost:9000/api/build" +NEXT_PUBLIC_JS_COMPILE_API_ENDPOINT="http://localhost:9000/api/build/js" NEXT_PUBLIC_COMPILE_API_BASE_URL="http://localhost:9000" NEXT_PUBLIC_LANGUAGE_SERVER_API_ENDPOINT="ws://localhost:9000/language-server/c" NEXT_PUBLIC_TESTNET_URL="xahau-test.net" diff --git a/.gitignore b/.gitignore index c98cdfc..e68f5bb 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ yarn-error.log* # yarn .yarnrc.yml .yarn/ + +# esbuild +public/esbuild.wasm diff --git a/components/DeployEditor.tsx b/components/DeployEditor.tsx index 2b13bb7..5aed6dd 100644 --- a/components/DeployEditor.tsx +++ b/components/DeployEditor.tsx @@ -31,7 +31,8 @@ const DeployEditor = () => { const renderNav = () => ( (state.activeWat = idx)}> {compiledFiles.map((file, index) => { - return + const compiledViewableExtension = file.compiledExtension === 'wasm' ? 'wat' : 'js' + return })} ) @@ -41,8 +42,8 @@ const DeployEditor = () => { compiledSize > FILESIZE_BREAKPOINTS[1] ? '$error' : compiledSize > FILESIZE_BREAKPOINTS[0] - ? '$warning' - : '$success' + ? '$warning' + : '$success' const isContentChanged = activeFile && activeFile.compiledValueSnapshot !== activeFile.content // const hasDeployErrors = activeFile && activeFile.containsErrors; @@ -58,7 +59,7 @@ const DeployEditor = () => { }} > - Compiled {activeFile.name.split('.')[0] + '.wasm'} + Compiled {activeFile.name.split('.')[0] + '.' + activeFile.compiledExtension} {activeFile?.lastCompiled && } {activeFile.compiledContent?.byteLength && ( @@ -73,7 +74,7 @@ const DeployEditor = () => { )} {isContentChanged && ( @@ -128,14 +129,14 @@ const DeployEditor = () => { ) : ( { - monaco.languages.register({ id: 'wat' }) - monaco.languages.setLanguageConfiguration('wat', wat.config) - monaco.languages.setMonarchTokensProvider('wat', wat.tokens) + monaco.languages.register({ id: activeFile.language }) + monaco.languages.setLanguageConfiguration(activeFile.language, wat.config) + monaco.languages.setMonarchTokensProvider(activeFile.language, wat.tokens) }} onMount={editor => { editor.updateOptions({ diff --git a/components/HooksEditor.tsx b/components/HooksEditor.tsx index 2128f35..a3bdd0f 100644 --- a/components/HooksEditor.tsx +++ b/components/HooksEditor.tsx @@ -200,15 +200,15 @@ const HooksEditor = () => { defaultValue={file?.content} // onChange={val => (state.files[snap.active].content = val)} // Auto save? beforeMount={monaco => { - // if (!snap.editorCtx) { - // snap.files.forEach(file => - // monaco.editor.createModel( - // file.content, - // file.language, - // monaco.Uri.parse(`file:///work/c/${file.name}`) - // ) - // ) - // } + if (!snap.editorCtx) { + snap.files.forEach(file => + monaco.editor.createModel( + file.content, + file.language, + monaco.Uri.parse(`file:///work/c/${file.name}`) + ) + ) + } // create the web socket if (!subscriptionRef.current) { @@ -223,6 +223,21 @@ const HooksEditor = () => { extensions: ['.txt'], mimetypes: ['text/plain'], }) + + monaco.languages.register({ + id: 'typescript', + extensions: ['.ts', '.js'], + mimetypes: ['text/plain'], + }) + + // Set global variables + snap.files.filter(file => file.content.includes('declare global')) + .forEach(file => { + monaco.languages.typescript.javascriptDefaults.addExtraLib( + file.content + ) + }) + MonacoServices.install(monaco) const webSocket = createWebSocket( process.env.NEXT_PUBLIC_LANGUAGE_SERVER_API_ENDPOINT || '' diff --git a/components/Navigation.tsx b/components/Navigation.tsx index e4e9d23..36918e9 100644 --- a/components/Navigation.tsx +++ b/components/Navigation.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useState } from 'react' import Link from 'next/link' import { useSnapshot } from 'valtio' @@ -27,8 +27,9 @@ import { DialogTrigger } from './Dialog' import PanelBox from './PanelBox' -import { templateFileIds } from '../state/constants' +import { templateCFileIds, templateJSFileIds } from '../state/constants' import { styled } from '../stitches.config' +import { Tab, Tabs } from './Tabs' const ImageWrapper = styled(Flex, { position: 'relative', @@ -45,9 +46,17 @@ const ImageWrapper = styled(Flex, { } }) +const cEnabled = !!process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT +const jsEnabled = !!process.env.NEXT_PUBLIC_JS_COMPILE_API_ENDPOINT + +type Languages = 'C' | 'JavaScript' + +const defaultLanguage: Languages = cEnabled ? 'C' : 'JavaScript' + const Navigation = () => { const router = useRouter() const snap = useSnapshot(state) + const [language, setLanguage] = useState(defaultLanguage) const slug = router.query?.slug const gistId = Array.isArray(slug) ? slug[0] : null @@ -261,34 +270,64 @@ const Navigation = () => { - {Object.values(templateFileIds).map(template => ( - - {template.icon()} - {template.name} + {cEnabled && jsEnabled && ( + + setLanguage(header as Languages)}> + + + + + )} + + {language === 'C' ? Object.values(templateCFileIds).map(template => ( + + {template.icon()} + {template.name} + + {template.description} + + )) : Object.values(templateJSFileIds).map(template => ( + + {template.icon()} + {template.name} - {template.description} - - ))} + {template.description} + + ))} + diff --git a/components/RunScript/index.tsx b/components/RunScript/index.tsx index c26cf99..91a2c81 100644 --- a/components/RunScript/index.tsx +++ b/components/RunScript/index.tsx @@ -214,7 +214,7 @@ const RunScript: React.FC<{ file: IFile }> = ({ file: { content, name } }) => { setIframeCode('') }} > - {name} + Run Script diff --git a/components/SetHookDialog.tsx b/components/SetHookDialog.tsx index b10d524..d9cf510 100644 --- a/components/SetHookDialog.tsx +++ b/components/SetHookDialog.tsx @@ -276,8 +276,41 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( + {activeFile?.language === 'javascript' && + + + + { + if (e.key === '.' || e.key === ',') { + e.preventDefault() + } + }} + step="1" + defaultValue={10000} + css={{ + '-moz-appearance': 'textfield', + '&::-webkit-outer-spin-button': { + '-webkit-appearance': 'none', + margin: 0 + }, + '&::-webkit-inner-spin-button ': { + '-webkit-appearance': 'none', + margin: 0 + } + }} + /> + + {errors.JSHookFee?.type === 'required' && ( + Hook Fee is required + )} + + } - + = React.memo( setValue('Fee', Math.round(Number(res.base_fee || '')).toString()) } } - } catch (err) {} + } catch (err) { } setEstimateLoading(false) }} @@ -338,7 +371,7 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo( {errors.Fee?.type === 'required' && ( - Fee is required + SetHook Fee is required )} {/* diff --git a/components/Tabs.tsx b/components/Tabs.tsx index c0ff81f..a687dbe 100644 --- a/components/Tabs.tsx +++ b/components/Tabs.tsx @@ -43,6 +43,7 @@ interface Props { regex: string | RegExp error: string } + css?: Record onCreateNewTab?: (name: string) => any onRenameTab?: (index: number, nwName: string, oldName?: string) => any onCloseTab?: (index: number, header?: string) => any @@ -65,7 +66,8 @@ export const Tabs = ({ headerExtraValidation, extensionRequired, defaultExtension = '', - allowedExtensions + allowedExtensions, + css }: Props) => { const [active, setActive] = useState(activeIndex || 0) const tabs: TabProps[] = children.map(elem => elem.props) @@ -205,7 +207,8 @@ export const Tabs = ({ flexWrap: 'nowrap', marginBottom: '$2', width: '100%', - overflow: 'auto' + overflow: 'auto', + ...css }} > {tabs.map((tab, idx) => ( @@ -347,28 +350,28 @@ export const Tabs = ({ )} {keepAllAlive ? tabs.map((tab, idx) => { - // TODO Maybe rule out fragments as children - if (!isValidElement(tab.children)) { - if (active !== idx) return null - return tab.children - } - let key = tab.children.key || tab.header || idx - let { children } = tab - let { style, ...props } = children.props - return ( - - ) - }) + // TODO Maybe rule out fragments as children + if (!isValidElement(tab.children)) { + if (active !== idx) return null + return tab.children + } + let key = tab.children.key || tab.header || idx + let { children } = tab + let { style, ...props } = children.props + return ( + + ) + }) : tabs[active] && ( - {tabs[active].children} - )} + {tabs[active].children} + )} ) } diff --git a/content/transactions.json b/content/transactions.json index 18e29cd..ba07b0f 100644 --- a/content/transactions.json +++ b/content/transactions.json @@ -30,7 +30,7 @@ "Account": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy", "TransactionType": "CheckCash", "Amount": { - "$value": "100", + "$value": "1", "$type": "amount.xrp" }, "DeliverMin": { @@ -75,7 +75,7 @@ "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "TransactionType": "EscrowCreate", "Amount": { - "$value": "100", + "$value": "1", "$type": "amount.xrp" }, "Destination": { @@ -138,7 +138,7 @@ "$value": "" }, "Amount": { - "$value": "100", + "$value": "1", "$type": "amount.xrp" }, "Fee": "12", @@ -149,7 +149,7 @@ "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "TransactionType": "PaymentChannelCreate", "Amount": { - "$value": "100", + "$value": "1", "$type": "amount.xrp" }, "Destination": { @@ -168,7 +168,7 @@ "TransactionType": "PaymentChannelFund", "Channel": "C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198", "Amount": { - "$value": "200", + "$value": "2", "$type": "amount.xrp" }, "Expiration": 543171558, @@ -262,7 +262,7 @@ "URITokenID": "B792B56B558C89C4E942E41B5DB66074E005CB198DB70C26C707AAC2FF5F74CB", "Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "Amount": { - "$value": "100", + "$value": "1", "$type": "amount.xrp" }, "Fee": "10", @@ -280,10 +280,10 @@ "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", "URITokenID": "B792B56B558C89C4E942E41B5DB66074E005CB198DB70C26C707AAC2FF5F74CB", "Amount": { - "$value": "100", + "$value": "1", "$type": "amount.xrp" }, "Fee": "10", "Sequence": 1 } -] \ No newline at end of file +] diff --git a/next.config.js b/next.config.js index 8b0f92e..e78bb79 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,6 @@ +const CopyPlugin = require('copy-webpack-plugin'); +const path = require('path'); + /** @type {import('next').NextConfig} */ module.exports = { reactStrictMode: true, @@ -15,6 +18,18 @@ module.exports = { test: [/\.md$/, /hook-bundle\.js$/], use: 'raw-loader' }) + if (!isServer) { + config.plugins.push( + new CopyPlugin({ + patterns: [ + { + from: path.resolve(__dirname, 'node_modules/esbuild-wasm/esbuild.wasm'), + to: path.resolve(__dirname, 'public/esbuild.wasm') + } + ] + }) + ); + } return config } } diff --git a/package.json b/package.json index fc9dc98..82af27e 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "base64-js": "^1.5.1", "comment-parser": "^1.3.1", "dinero.js": "^1.9.1", + "esbuild-wasm": "^0.24.2", "file-saver": "^2.0.5", "filesize": "^8.0.7", "javascript-time-ago": "^2.3.11", @@ -38,7 +39,7 @@ "lodash.xor": "^4.5.0", "monaco-editor": "^0.33.0", "next": "^12.0.4", - "next-auth": "^4.10.3", + "next-auth": "^4.24.11", "next-plausible": "^3.2.0", "next-themes": "^0.1.1", "normalize-url": "^7.0.2", @@ -77,12 +78,16 @@ "@types/pako": "^1.0.2", "@types/react": "17.0.31", "browserify": "^17.0.0", + "copy-webpack-plugin": "^12.0.2", "eslint": "7.32.0", "eslint-config-next": "11.1.2", "raw-loader": "^4.0.2", - "typescript": "4.4.4" + "typescript": "^4.9.5" }, "resolutions": { "ripple-binary-codec": "=1.6.0" + }, + "engines": { + "node": ">=22.0.0" } } diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 94345ea..d47067b 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -1,5 +1,11 @@ import NextAuth from 'next-auth' +declare module "next-auth" { + interface User { + username: string + } +} + export default NextAuth({ // Configure one or more authentication providers providers: [ diff --git a/pages/develop/[[...slug]].tsx b/pages/develop/[[...slug]].tsx index e3af2f3..150a48c 100644 --- a/pages/develop/[[...slug]].tsx +++ b/pages/develop/[[...slug]].tsx @@ -150,7 +150,7 @@ const Home: NextPage = () => { const activeFile = snap.files[snap.active] as IFile | undefined const activeFileExt = getFileExtention(activeFile?.name) - const canCompile = activeFileExt === 'c' || activeFileExt === 'wat' + const canCompile = ['c', 'wat', 'js', 'ts'].includes(activeFileExt || '') return ( { >
- {canCompile && ( - !snap.compiling && snap.files.length && compileCode(snap.active)} - > - + {canCompile && ( + !snap.compiling && snap.files.length && compileCode(snap.active)} > - - }> - - - - - )} - {activeFileExt === 'js' && ( - !snap.compiling && snap.files.length && compileCode(snap.active)} - > - }> + + + )} + + )} + {activeFileExt === 'js' && ( + !snap.compiling && snap.files.length && compileCode(snap.active)} > - - - - )} + + + )} +
{ // Save the file to global state saveFile(false, activeId) + const file = state.files[activeId] - if (file.name.endsWith('.wat')) { - return compileWat(activeId) - } - if (!process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT) { - throw Error('Missing env!') - } // Bail out if we're already compiling if (state.compiling) { // if compiling is ongoing return // TODO Inform user about it. @@ -31,6 +28,66 @@ export const compileCode = async (activeId: number) => { // Set loading state to true state.compiling = true state.logs = [] + + if (file.name.endsWith('.wat')) { + return compileWat(activeId) + } + + if (file.name.endsWith('.js') || file.name.endsWith('.ts')) { + return compileJs(activeId) + } + + return compileC(activeId) +} + +export const compileWat = async (activeId: number) => { + const file = state.files[activeId] + try { + const wabt = await (await import('wabt')).default() + const module = wabt.parseWat(file.name, file.content); + module.resolveNames(); + module.validate(); + const { buffer } = module.toBinary({ + log: false, + write_debug_names: true, + }); + + file.compiledContent = ref(buffer) + file.lastCompiled = new Date() + file.compiledValueSnapshot = file.content + file.compiledWatContent = file.content + file.compiledExtension = 'wasm' + + toast.success('Compiled successfully!', { position: 'bottom-center' }) + state.logs.push({ + type: 'success', + message: `File ${state.files?.[activeId]?.name} compiled successfully. Ready to deploy.`, + link: Router.asPath.replace('develop', 'deploy'), + linkText: 'Go to deploy' + }) + } catch (err) { + console.log(err) + let message = "Error compiling WAT file!" + if (err instanceof Error) { + message = err.message + } + state.logs.push({ + type: 'error', + message + }) + toast.error(`Error occurred while compiling!`, { position: 'bottom-center' }) + file.containsErrors = true + } + state.compiling = false +} + +export const compileC = async (activeId: number) => { + const file = state.files[activeId] + + if (!process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT) { + throw Error('Missing env!') + } + try { file.containsErrors = false let res: Response @@ -88,6 +145,7 @@ export const compileCode = async (activeId: number) => { file.lastCompiled = new Date() file.compiledValueSnapshot = file.content file.compiledWatContent = wast + file.compiledExtension = 'wasm' } catch (error) { throw Error('Invalid compilation result produced, check your code for errors and try again!') } @@ -127,25 +185,157 @@ export const compileCode = async (activeId: number) => { } } -export const compileWat = async (activeId: number) => { - if (state.compiling) return; +function customResolver(tree: Record): esbuild.Plugin { + const map = new Map(Object.entries(tree)) + return { + name: 'example', + setup: (build: esbuild.PluginBuild) => { + build.onResolve({ filter: /.*/, }, (args: esbuild.OnResolveArgs) => { + if (args.kind === 'entry-point') { + return { path: '/' + args.path } + } + if (args.kind === 'import-statement') { + const dirname = Path.dirname(args.importer) + const basePath = Path.join(dirname, args.path) + // If extension is specified, try that path directly + if (Path.extname(args.path)) { + return { path: basePath } + } + // If no extension specified, try .ts and .js in order + const extensions = ['.ts', '.js'] + for (const ext of extensions) { + const pathWithExt = basePath + ext + if (map.has(pathWithExt.replace(/^\//, ''))) { + return { path: pathWithExt } + } + } + } + throw Error('not resolvable') + }) + + build.onLoad({ filter: /.*/ }, (args: esbuild.OnLoadArgs) => { + const path = args.path.replace(/^\//, '') + if (!map.has(path)) { + throw Error('not loadable') + } + const ext = Path.extname(path) + const contents = map.get(path)! + const loader = (ext === '.ts') ? 'ts' : + (ext === '.js') ? 'js' : + 'default' + return { contents, loader } + }) + } + } +} + +function validateExportContent(content: string): void { + const words = content + .split(",") + .map((word) => word.trim()) + .filter((word) => word.length > 0); + if (!words.includes("Hook")) { + throw Error("Invalid export: Hook is required"); + } + if (!words.every((word) => word === "Hook" || word === "Callback")) { + throw Error("Invalid export: Only Hook and Callback are allowed"); + } +} + + +function clean(content: string): string { + const importPattern = /^\s*import\s+.*?;\s*$/gm; + const exportPattern = /^\s*export\s*\{([^}]*)\};?\s*$/gm; + const commentPattern = /^\s*\/\/.*$/gm; + + const match = exportPattern.exec(content); + if (!match) { + throw Error("Invalid export: No export found"); + } + const exportContent = match[1]; + validateExportContent(exportContent); + let cleanedCode = content.replace(importPattern, ""); + cleanedCode = cleanedCode.replace(exportPattern, ""); + cleanedCode = cleanedCode.replace(commentPattern, ""); + cleanedCode = cleanedCode.trim(); + return cleanedCode; +} + +export const compileJs = async (activeId: number) => { const file = state.files[activeId] - state.compiling = true - state.logs = [] + + if (!process.env.NEXT_PUBLIC_JS_COMPILE_API_ENDPOINT) { + throw Error('Missing env!') + } + + const tree = state.files.reduce((prev, file) => { + prev[file.name] = file.content + return prev + }, {} as Record) + + if (!(window as any).isEsbuildRunning) { + (window as any).isEsbuildRunning = true + await esbuild.initialize({ + wasmURL: '/esbuild.wasm', + }) + } + try { - const wabt = await (await import('wabt')).default() - const module = wabt.parseWat(file.name, file.content); - module.resolveNames(); - module.validate(); - const { buffer } = module.toBinary({ - log: false, - write_debug_names: true, - }); + const result = await esbuild.build({ + entryPoints: [file.name], + bundle: true, + format: "esm", + write: false, + plugins: [customResolver(tree)] + }) - file.compiledContent = ref(buffer) + let compiledContent = clean(result.outputFiles?.[0].text) + file.language = 'javascript' + const res = await fetch(process.env.NEXT_PUBLIC_JS_COMPILE_API_ENDPOINT, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + output: 'bc', + compress: true, + strip: true, + files: [ + { + type: 'js', + options: '-O3', + name: file.name, + src: compiledContent + } + ] + }) + }) + + const json = await res.json() + + state.compiling = false + if (!json.success) { + const errors = [json.message] + if (json.tasks && json.tasks.length > 0) { + json.tasks.forEach((task: any) => { + if (!task.success) { + errors.push(task?.console) + } + }) + } + throw errors + } + + if (!json.success) { + throw new Error(json.error || 'Failed to compile JavaScript') + } + + const binary = await decodeBinary(json.output) + file.compiledContent = ref(binary) file.lastCompiled = new Date() file.compiledValueSnapshot = file.content - file.compiledWatContent = file.content + file.compiledWatContent = compiledContent + file.compiledExtension = 'js' toast.success('Compiled successfully!', { position: 'bottom-center' }) state.logs.push({ @@ -156,16 +346,28 @@ export const compileWat = async (activeId: number) => { }) } catch (err) { console.log(err) - let message = "Error compiling WAT file!" - if (err instanceof Error) { - message = err.message + + if (err instanceof Array && typeof err[0] === 'string') { + err.forEach(message => { + state.logs.push({ + type: 'error', + message + }) + }) + } else if (err instanceof Error) { + state.logs.push({ + type: 'error', + message: err.message + }) + } else { + state.logs.push({ + type: 'error', + message: 'Something went wrong, come back later!' + }) } - state.logs.push({ - type: 'error', - message - }) + + state.compiling = false toast.error(`Error occurred while compiling!`, { position: 'bottom-center' }) file.containsErrors = true } - state.compiling = false } diff --git a/state/actions/deployHook.tsx b/state/actions/deployHook.tsx index e7dd322..302d2b1 100644 --- a/state/actions/deployHook.tsx +++ b/state/actions/deployHook.tsx @@ -91,8 +91,9 @@ export const prepareDeployHookTx = async ( CreateCode: arrayBufferToHex(activeFile?.compiledContent).toUpperCase(), HookOn: calculateHookOn(hookOnValues), HookNamespace, - HookApiVersion: 0, + HookApiVersion: activeFile.language === 'javascript' ? 1 : 0, Flags: 1, + Fee: data.JSHookFee, // ...(filteredHookGrants.length > 0 && { HookGrants: filteredHookGrants }), ...(filteredHookParameters.length > 0 && { HookParameters: filteredHookParameters @@ -241,9 +242,8 @@ export const deleteHook = async (account: IAccount & { name?: string }) => { }) state.deployLogs.push({ type: 'error', - message: `[${submitRes.engine_result || submitRes.error}] ${ - submitRes.engine_result_message || submitRes.error_exception - }` + message: `[${submitRes.engine_result || submitRes.error}] ${submitRes.engine_result_message || submitRes.error_exception + }` }) } } catch (err) { diff --git a/state/actions/fetchFiles.ts b/state/actions/fetchFiles.ts index fc6fd00..5c4a139 100644 --- a/state/actions/fetchFiles.ts +++ b/state/actions/fetchFiles.ts @@ -1,9 +1,37 @@ import { Octokit } from '@octokit/core' import state, { IFile } from '../index' -import { templateFileIds } from '../constants' +import { templateCFileIds, templateJSFileIds } from '../constants' const octokit = new Octokit() +const fileNameToFile = (files: any, filename: string) => ({ + name: files[filename]?.filename || 'untitled.c', + language: files[filename]?.language?.toLowerCase() || '', + content: files[filename]?.content || '' +}) + +const sortFiles = (a: IFile, b: IFile) => { + const aBasename = a.name.split('.')?.[0] + const aExt = a.name.split('.').pop() || '' + const bBasename = b.name.split('.')?.[0] + const bExt = b.name.split('.').pop() || '' + + // default priority is undefined == 0 + const extPriority: Record = { + c: 3, + wat: 3, + md: 2, + h: -1 + } + + // Sort based on extention priorities + const comp = (extPriority[bExt] || 0) - (extPriority[aExt] || 0) + if (comp !== 0) return comp + + // Otherwise fallback to alphabetical sorting + return aBasename.localeCompare(bBasename) +} + /** * Fetches files from Github Gists based on gistId and stores them in global state */ @@ -17,62 +45,70 @@ export const fetchFiles = async (gistId: string) => { }) try { const res = await octokit.request('GET /gists/{gist_id}', { gist_id: gistId }) + if (!res.data.files) throw Error('No files could be fetched from given gist id!') + + const isCTemplate = (id: string) => + Object.values(templateCFileIds) + .map(v => v.id) + .includes(id) - const isTemplate = (id: string) => - Object.values(templateFileIds) + const isJSTemplate = (id: string) => + Object.values(templateJSFileIds) .map(v => v.id) .includes(id) - if (isTemplate(gistId)) { - // fetch headers - const headerRes = await fetch( - `${process.env.NEXT_PUBLIC_COMPILE_API_BASE_URL}/api/header-files` - ) - if (!headerRes.ok) throw Error('Failed to fetch headers') + let files: IFile[] = [] - const headerJson = await headerRes.json() - const headerFiles: Record = + if (isCTemplate(gistId)) { + const template = Object.values(templateCFileIds).find(tmp => tmp.id === gistId) + let headerFiles: Record = {} - Object.entries(headerJson).forEach(([key, value]) => { - const fname = `${key}.h` - headerFiles[fname] = { filename: fname, content: value as string, language: 'C' } - }) - const files = { + if (template?.headerId) { + const resHeader = await octokit.request('GET /gists/{gist_id}', { gist_id: template.headerId }) + if (!resHeader.data.files) throw new Error('No header files could be fetched from given gist id!') + headerFiles = resHeader.data.files as any + } else { + // fetch headers + const headerRes = await fetch( + `${process.env.NEXT_PUBLIC_COMPILE_API_BASE_URL}/api/header-files` + ) + if (!headerRes.ok) throw Error('Failed to fetch headers') + + const headerJson = await headerRes.json() + Object.entries(headerJson).forEach(([key, value]) => { + const fname = `${key}.h` + headerFiles[fname] = { filename: fname, content: value as string, language: 'C' } + }) + } + const _files = { ...res.data.files, ...headerFiles } - res.data.files = files - } - - if (!res.data.files) throw Error('No files could be fetched from given gist id!') - - const files: IFile[] = Object.keys(res.data.files).map(filename => ({ - name: res.data.files?.[filename]?.filename || 'untitled.c', - language: res.data.files?.[filename]?.language?.toLowerCase() || '', - content: res.data.files?.[filename]?.content || '' - })) - - files.sort((a, b) => { - const aBasename = a.name.split('.')?.[0] - const aExt = a.name.split('.').pop() || '' - const bBasename = b.name.split('.')?.[0] - const bExt = b.name.split('.').pop() || '' - - // default priority is undefined == 0 - const extPriority: Record = { - c: 3, - wat: 3, - md: 2, - h: -1 + files = Object.keys(_files) + .map((filename) => fileNameToFile(_files, filename)) + files.sort(sortFiles) + } else if (isJSTemplate(gistId)) { + // fetch JS headers(eg. global.d.ts) + const template = Object.values(templateJSFileIds).find(tmp => tmp.id === gistId) + if (template?.headerId) { + const resHeader = await octokit.request('GET /gists/{gist_id}', { gist_id: template.headerId }) + if (!resHeader.data.files) throw Error('No header files could be fetched from given gist id!') + files = Object.keys(resHeader.data.files) + .map((filename) => fileNameToFile(resHeader.data.files, filename)) + files.sort(sortFiles) } - // Sort based on extention priorities - const comp = (extPriority[bExt] || 0) - (extPriority[aExt] || 0) - if (comp !== 0) return comp - - // Otherwise fallback to alphabetical sorting - return aBasename.localeCompare(bBasename) - }) + // Put entry point files at the beginning + files = [ + ...Object.keys(res.data.files).map((filename) => fileNameToFile(res.data.files, filename)), + ...files + ] + } else { + const _files = res.data.files + files = Object.keys(_files) + .map((filename) => fileNameToFile(_files, filename)) + files.sort(sortFiles) + } state.logs.push({ type: 'success', diff --git a/state/constants/templates.ts b/state/constants/templates.ts index 2b4a5de..fd19e13 100644 --- a/state/constants/templates.ts +++ b/state/constants/templates.ts @@ -4,38 +4,69 @@ import Notary from '../../components/icons/Notary' import Peggy from '../../components/icons/Peggy' import Starter from '../../components/icons/Starter' -export const templateFileIds = { +type Template = { + id: string + name: string + description: string + headerId?: string + icon: () => JSX.Element +} + +export const templateCFileIds: Record = { starter: { id: '1f8109c80f504e6326db2735df2f0ad6', // Forked name: 'Starter', description: 'Just a basic starter with essential imports, just accepts any transaction coming through', + headerId: '028e8ce6d6d674776970caf8acc77ecc', icon: Starter }, firewall: { id: '1cc30f39c8a0b9c55b88c312669ca45e', // Forked name: 'Firewall', description: 'This Hook essentially checks a blacklist of accounts', + headerId: '028e8ce6d6d674776970caf8acc77ecc', icon: Firewall }, notary: { id: '87b6f5a8c2f5038fb0f20b8b510efa10', // Forked name: 'Notary', description: 'Collecting signatures for multi-sign transactions', + headerId: '028e8ce6d6d674776970caf8acc77ecc', icon: Notary }, carbon: { id: '953662b22d065449f8ab6f69bc2afe41', // Forked name: 'Carbon', description: 'Send a percentage of sum to an address', + headerId: '028e8ce6d6d674776970caf8acc77ecc', icon: Carbon }, peggy: { id: '049784a83fa068faf7912f663f7b6471', // Forked name: 'Peggy', description: 'An oracle based stable coin hook', + headerId: '028e8ce6d6d674776970caf8acc77ecc', icon: Peggy } } +export const templateJSFileIds: Record = { + starter: { + id: '894137a0ebd67568c877237140f4586f', + name: 'Starter', + description: + 'Just a basic starter with essential imports, just accepts any transaction coming through', + headerId: 'e64b8286f04b3ab84cab63ec3abd8771', + icon: Starter + }, + carbon: { + id: '9fa48d4fba17b2bbe2148eb9c3f15914', + name: 'Carbon', + description: 'Send a percentage of sum to an address', + headerId: 'e64b8286f04b3ab84cab63ec3abd8771', + icon: Carbon + } +} + export const apiHeaderFiles = ['hookapi.h', 'sfcodes.h', 'macro.h', 'extern.h', 'error.h'] diff --git a/state/index.ts b/state/index.ts index d317655..b0d9101 100644 --- a/state/index.ts +++ b/state/index.ts @@ -13,6 +13,7 @@ export interface IFile { name: string language: string content: string + compiledExtension?: 'wasm' | 'js' compiledValueSnapshot?: string compiledContent?: ArrayBuffer | null compiledWatContent?: string | null diff --git a/utils/setHook.ts b/utils/setHook.ts index 2a0e562..db441db 100644 --- a/utils/setHook.ts +++ b/utils/setHook.ts @@ -11,6 +11,7 @@ export type SetHookData = { value: keyof TTS label: string }[] + JSHookFee?: string Fee: string HookNamespace: string HookParameters: { @@ -90,4 +91,4 @@ export function fromHex(hex: string) { str += String.fromCharCode(parseInt(hex.substring(i, i + 2), 16)) } return str -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index a5192a9..9e95323 100644 --- a/yarn.lock +++ b/yarn.lock @@ -64,6 +64,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.20.13": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.7.tgz#f4e7fe527cd710f8dc0618610b61b4b060c3c341" + integrity sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/types@^7.16.7": version "7.17.0" resolved "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz" @@ -530,10 +537,10 @@ "@octokit/webhooks-types" "5.2.0" aggregate-error "^3.1.0" -"@panva/hkdf@^1.0.1": - version "1.0.1" - resolved "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.1.tgz" - integrity sha512-mMyQ9vjpuFqePkfe5bZVIf/H3Dmk6wA8Kjxff9RcO4kqzJo+Ek9pGKwZHpeMr7Eku0QhLXMCd7fNCSnEnRMubg== +"@panva/hkdf@^1.0.2": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.2.1.tgz#cb0d111ef700136f4580349ff0226bf25c853f23" + integrity sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw== "@radix-ui/colors@^0.1.7": version "0.1.8" @@ -929,6 +936,11 @@ resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.0.tgz" integrity sha512-JLo+Y592QzIE+q7Dl2pMUtt4q8SKYI5jDrZxrozEQxnGVOyYE+GWK9eLkwTaeN9DDctlaRAQ3TBmzZ1qdLE30A== +"@sindresorhus/merge-streams@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" + integrity sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg== + "@stitches/react@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@stitches/react/-/react-1.2.8.tgz#954f8008be8d9c65c4e58efa0937f32388ce3a38" @@ -980,6 +992,11 @@ resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/json-schema@^7.0.9": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" @@ -1206,11 +1223,25 @@ aggregate-error@^3.1.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -1221,6 +1252,16 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.0, ajv@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ajv@^8.0.1: version "8.10.0" resolved "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz" @@ -1485,6 +1526,13 @@ braces@^3.0.1: dependencies: fill-range "^7.0.1" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + brorand@^1.0.1, brorand@^1.0.5, brorand@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" @@ -1832,10 +1880,22 @@ convert-source-map@~1.1.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" integrity sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg== -cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +cookie@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + +copy-webpack-plugin@^12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz#935e57b8e6183c82f95bd937df658a59f6a2da28" + integrity sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA== + dependencies: + fast-glob "^3.3.2" + glob-parent "^6.0.1" + globby "^14.0.0" + normalize-path "^3.0.0" + schema-utils "^4.2.0" + serialize-javascript "^6.0.2" core-js-pure@^3.20.2: version "3.21.1" @@ -2223,6 +2283,11 @@ es6-symbol@^3.1.1, es6-symbol@^3.1.3: d "^1.0.1" ext "^1.1.2" +esbuild-wasm@^0.24.2: + version "0.24.2" + resolved "https://registry.yarnpkg.com/esbuild-wasm/-/esbuild-wasm-0.24.2.tgz#1ab3b4b858ecf226a3c1a63455358ecea704c500" + integrity sha512-03/7Z1gD+ohDnScFztvI4XddTAbKVmMEzCvvkBpQdWKEXJ+73dTyeNrmdxP1Q0zpDMFjzUJwtK4rLjqwiHbzkw== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" @@ -2492,6 +2557,17 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.2, fast-glob@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" @@ -2512,6 +2588,11 @@ fast-safe-stringify@^2.0.7: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + fastq@^1.6.0: version "1.13.0" resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" @@ -2548,6 +2629,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-root@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" @@ -2648,6 +2736,13 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" @@ -2708,6 +2803,18 @@ globby@^11.0.3: merge2 "^1.4.1" slash "^3.0.0" +globby@^14.0.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-14.1.0.tgz#138b78e77cf5a8d794e327b15dce80bf1fb0a73e" + integrity sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA== + dependencies: + "@sindresorhus/merge-streams" "^2.1.0" + fast-glob "^3.3.3" + ignore "^7.0.3" + path-type "^6.0.0" + slash "^5.1.0" + unicorn-magic "^0.3.0" + goober@^2.1.1: version "2.1.8" resolved "https://registry.npmjs.org/goober/-/goober-2.1.8.tgz" @@ -2828,6 +2935,11 @@ ignore@^5.2.0: resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +ignore@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.3.tgz#397ef9315dfe0595671eefe8b633fec6943ab733" + integrity sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" @@ -3122,10 +3234,10 @@ javascript-time-ago@^2.3.11: dependencies: relative-time-format "^1.0.7" -jose@^4.1.4, jose@^4.3.7: - version "4.10.0" - resolved "https://registry.yarnpkg.com/jose/-/jose-4.10.0.tgz#2e0b7bcc80dd0775f8a4588e55beb9460c37d60a" - integrity sha512-KEhB/eLGLomWGPTb+/RNbYsTjIyx03JmbqAyIyiXBuNSa7CmNrJd5ysFhblayzs/e/vbOPMUaLnjHUMhGp4yLw== +jose@^4.15.5, jose@^4.15.9: + version "4.15.9" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.9.tgz#9b68eda29e9a0614c042fa29387196c7dd800100" + integrity sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -3671,6 +3783,14 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -3772,17 +3892,17 @@ natural-compare@^1.4.0: resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -next-auth@^4.10.3: - version "4.10.3" - resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.10.3.tgz#0a952dd5004fd2ac2ba414c990922cf9b33951a3" - integrity sha512-7zc4aXYc/EEln7Pkcsn21V1IevaTZsMLJwapfbnKA4+JY0+jFzWbt5p/ljugesGIrN4VOZhpZIw50EaFZyghJQ== +next-auth@^4.24.11: + version "4.24.11" + resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.24.11.tgz#16eeb76d37fbc8fe887561b454f8167f490c381f" + integrity sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw== dependencies: - "@babel/runtime" "^7.16.3" - "@panva/hkdf" "^1.0.1" - cookie "^0.4.1" - jose "^4.3.7" + "@babel/runtime" "^7.20.13" + "@panva/hkdf" "^1.0.2" + cookie "^0.7.0" + jose "^4.15.5" oauth "^0.9.15" - openid-client "^5.1.0" + openid-client "^5.4.0" preact "^10.6.3" preact-render-to-string "^5.1.19" uuid "^8.3.2" @@ -3842,6 +3962,11 @@ node-gyp-build@^4.3.0: resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz" integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + normalize-url@^7.0.2: version "7.0.3" resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-7.0.3.tgz" @@ -3857,9 +3982,9 @@ object-assign@^4.1.1: resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-hash@^2.0.1: +object-hash@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== object-inspect@^1.11.0, object-inspect@^1.9.0: @@ -3939,10 +4064,10 @@ octokit@^1.7.0: "@octokit/plugin-throttling" "^3.5.1" "@octokit/types" "^6.26.0" -oidc-token-hash@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz" - integrity sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ== +oidc-token-hash@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz#9a229f0a1ce9d4fc89bcaee5478c97a889e7b7b6" + integrity sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw== once@^1.3.0, once@^1.4.0: version "1.4.0" @@ -3959,15 +4084,15 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" -openid-client@^5.1.0: - version "5.1.4" - resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.1.4.tgz" - integrity sha512-36/PZY3rDgiIFj2uCL9a1fILPmIwu3HksoWO4mukgXe74ZOsEisJMMqTMfmPNw6j/7kO0mBc2xqy4eYRrB8xPA== +openid-client@^5.4.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.7.1.tgz#34cace862a3e6472ed7d0a8616ef73b7fb85a9c3" + integrity sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew== dependencies: - jose "^4.1.4" + jose "^4.15.9" lru-cache "^6.0.0" - object-hash "^2.0.1" - oidc-token-hash "^5.0.1" + object-hash "^2.2.0" + oidc-token-hash "^5.0.3" optionator@^0.9.1: version "0.9.1" @@ -4114,6 +4239,11 @@ path-type@^4.0.0: resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path-type@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-6.0.0.tgz#2f1bb6791a91ce99194caede5d6c5920ed81eb51" + integrity sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ== + pbkdf2@^3.0.3, pbkdf2@^3.0.9: version "3.1.2" resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" @@ -4140,7 +4270,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.2.3: +picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -4269,7 +4399,7 @@ raf@^3.4.1: dependencies: performance-now "^2.1.0" -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== @@ -4489,6 +4619,11 @@ regenerator-runtime@^0.13.4: resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regexify-string@^1.0.17: version "1.0.17" resolved "https://registry.npmjs.org/regexify-string/-/regexify-string-1.0.17.tgz" @@ -4731,6 +4866,16 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.3.0.tgz#3b669f04f71ff2dfb5aba7ce2d5a9d79b35622c0" + integrity sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" @@ -4748,6 +4893,13 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + set-immediate-shim@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz" @@ -4821,6 +4973,11 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slash@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" + integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== + slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" @@ -5166,10 +5323,10 @@ typeforce@^1.11.5: resolved "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz" integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== -typescript@4.4.4: - version "4.4.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz" - integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== umd@^3.0.0: version "3.0.3" @@ -5197,6 +5354,11 @@ undeclared-identifiers@^1.1.2: simple-concat "^1.0.0" xtend "^4.0.1" +unicorn-magic@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz#4efd45c85a69e0dd576d25532fbfa22aa5c8a104" + integrity sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA== + unified@^10.0.0: version "10.1.2" resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df"