objective categorical abstract machine language personal data server
65
fork

Configure Feed

Select the types of activity you want to include in your feed.

Get React working

futurGH 604ab928 8ac2703a

+1222 -692
+2
.gitignore
··· 5 5 dune.lock 6 6 dev-tools.locks 7 7 8 + node_modules 9 + 8 10 .DS_Store 9 11 .vscode/ 10 12 .idea/
+3 -2
bin/main.ml
··· 13 13 ; ( get 14 14 , "/.well-known/oauth-authorization-server" 15 15 , Api.Well_known.oauth_authorization_server ) 16 + ; (options, "/xrpc/**", Xrpc.handler (fun _ -> Dream.empty `No_Content)) 16 17 ; (* oauth *) 17 - (options, "/oauth/par", Api.Oauth_.Par.options_handler) 18 + (options, "/oauth/par", Xrpc.handler (fun _ -> Dream.empty `No_Content)) 18 19 ; (post, "/oauth/par", Api.Oauth_.Par.post_handler) 19 20 ; (get, "/oauth/authorize", Api.Oauth_.Authorize.get_handler) 20 21 ; (post, "/oauth/authorize", Api.Oauth_.Authorize.post_handler) 21 - ; (options, "/oauth/token", Api.Oauth_.Token.options_handler) 22 + ; (options, "/oauth/token", Xrpc.handler (fun _ -> Dream.empty `No_Content)) 22 23 ; (post, "/oauth/token", Api.Oauth_.Token.post_handler) 23 24 ; (* account *) 24 25 (get, "/account/login", Api.Account_.Login.get_handler)
+18 -1
dune
··· 18 18 -o 19 19 %{target}))))) 20 20 21 - (copy_files public/*) 21 + (subdir 22 + public/ 23 + (rule 24 + (alias client) 25 + (target client.js) 26 + (deps 27 + (:script ../frontend/build.mjs) 28 + (:entrypoints ../frontend/client/client/frontend/client/client.js) 29 + (source_tree ../frontend/client) 30 + (source_tree ../frontend/src)) 31 + (action 32 + (run 33 + node 34 + %{script} 35 + %{entrypoints} 36 + --output=./client.js 37 + --extract=true 38 + --env=%{env:NODE_ENV='production'}))))
+2
dune-project
··· 80 80 dune 81 81 lwt 82 82 melange 83 + melange-json 84 + melange-json-native 83 85 mlx 84 86 (reason-react (>= 0.16.0)) 85 87 (reason-react-ppx (>= 0.16.0))
+2
frontend.opam
··· 10 10 "dune" {>= "3.20"} 11 11 "lwt" 12 12 "melange" 13 + "melange-json" 14 + "melange-json-native" 13 15 "mlx" 14 16 "reason-react" {>= "0.16.0"} 15 17 "reason-react-ppx" {>= "0.16.0"}
+108
frontend/build.mjs
··· 1 + import { build as viteBuild } from "vite"; 2 + import resolve from "@rollup/plugin-node-resolve"; 3 + import path from "path"; 4 + 5 + async function build(entryPoints, { env, output }) { 6 + const outfile = output; 7 + const outdir = path.dirname(outfile); 8 + const splitting = true; 9 + 10 + const isDev = env === "development"; 11 + 12 + try { 13 + const result = await viteBuild({ 14 + build: { 15 + lib: { 16 + entry: entryPoints, 17 + formats: ["es"], 18 + fileName: "[name]", 19 + }, 20 + outDir: outdir, 21 + emptyOutDir: false, 22 + minify: isDev ? false : true, 23 + sourcemap: isDev, 24 + rollupOptions: { 25 + output: { 26 + entryFileNames: "[name].js", 27 + }, 28 + plugins: [resolve()], 29 + }, 30 + }, 31 + logLevel: "info", 32 + define: { 33 + "process.env.NODE_ENV": `"${env}"`, 34 + __DEV__: `"${isDev}"`, 35 + }, 36 + }); 37 + 38 + entryPoints.forEach((entryPoint) => { 39 + console.log( 40 + 'Build completed successfully for "' + entryPoint + '"', 41 + ); 42 + }); 43 + return result; 44 + } catch (error) { 45 + console.error("\nBuild failed:", error); 46 + process.exit(1); 47 + } 48 + } 49 + 50 + function parseArgv(argv) { 51 + const args = argv.slice(2); 52 + const result = { _: [] }; 53 + 54 + for (let i = 0; i < args.length; i++) { 55 + const arg = args[i]; 56 + 57 + if (arg.startsWith("--")) { 58 + const longArg = arg.slice(2); 59 + if (longArg.includes("=")) { 60 + const [key, value] = longArg.split("="); 61 + result[key] = parseValue(value); 62 + } else if (i + 1 < args.length && !args[i + 1].startsWith("-")) { 63 + result[longArg] = parseValue(args[++i]); 64 + } else { 65 + result[longArg] = true; 66 + } 67 + } else if (arg.startsWith("-")) { 68 + const shortArg = arg.slice(1); 69 + if (shortArg.includes("=")) { 70 + const [key, value] = shortArg.split("="); 71 + result[key] = parseValue(value); 72 + } else if (i + 1 < args.length && !args[i + 1].startsWith("-")) { 73 + result[shortArg] = parseValue(args[++i]); 74 + } else { 75 + for (const char of shortArg) { 76 + result[char] = true; 77 + } 78 + } 79 + } else { 80 + result._.push(parseValue(arg)); 81 + } 82 + } 83 + 84 + return result; 85 + } 86 + 87 + function parseValue(value) { 88 + if (value === "true") return true; 89 + if (value === "false") return false; 90 + if (value === "null") return null; 91 + if (!isNaN(value)) return Number(value); 92 + return value; 93 + } 94 + 95 + function camelCaseKeys(obj) { 96 + return Object.fromEntries( 97 + Object.entries(obj).map(([key, value]) => [ 98 + key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()), 99 + value, 100 + ]), 101 + ); 102 + } 103 + 104 + const flags = parseArgv(process.argv); 105 + const options = camelCaseKeys(flags); 106 + const entryPoints = options._; 107 + 108 + build(entryPoints, options);
+47
frontend/client/Router.mlx
··· 1 + open React 2 + 3 + module type Template = sig 4 + type props 5 + 6 + val props_of_json : Melange_json.t -> props 7 + 8 + val props_to_json : props -> Melange_json.t 9 + 10 + val [@react.component] make : props:props -> React.element 11 + end 12 + 13 + type route = {path: string; template: (module Template)} 14 + 15 + let routes = 16 + [ {path= "/oauth/authorize"; template= (module OauthAuthorizePage)} 17 + ; {path= "/account/login"; template= (module LoginPage)} ] 18 + 19 + let find_by_path path_to_find = 20 + List.find_opt (fun {path; _} -> path = path_to_find) routes 21 + 22 + let get_current_path () = [%mel.raw {| window.location.pathname |}] 23 + 24 + let render_page path props_json = 25 + match find_by_path path with 26 + | Some {template; _} -> ( 27 + let module Template = (val template) in 28 + try 29 + let props = Template.props_of_json props_json in 30 + <Template props /> 31 + with 32 + | Melange_json.Of_json_error err -> 33 + <div> 34 + (string 35 + ("parse error: " ^ Melange_json.of_json_error_to_string err) ) 36 + </div> 37 + | exn -> 38 + <div>(string ("render error: " ^ Printexc.to_string exn))</div> ) 39 + | _ -> 40 + <h1>(string "page not found")</h1> 41 + 42 + let[@react.component] make () = 43 + let path = get_current_path () in 44 + let props_json = 45 + [%mel.raw {| (window.__PAGE__ || {page: "", props: {}}).props |}] 46 + in 47 + render_page path props_json
+17
frontend/client/client.mlx
··· 1 + let () = 2 + try 3 + match ReactDOM.querySelector "#root" with 4 + | Some elem -> 5 + let _ = ReactDOM.Client.hydrateRoot elem <Router /> in 6 + () 7 + | None -> 8 + Js.log "No root element found" 9 + with exn -> ( 10 + match Js.Exn.asJsExn exn with 11 + | Some error -> 12 + Js.log2 "Error type:" (Js.Exn.name error) ; 13 + Js.log2 "Stack:" (Js.Exn.stack error) ; 14 + Js.log2 "Full error:" error 15 + | None -> 16 + Js.log "No JavaScript exception, got:" ; 17 + Js.log exn )
+21
frontend/client/dune
··· 1 + (melange.emit 2 + (target client) 3 + (module_systems es6) 4 + (libraries 5 + melange 6 + melange-json 7 + melange-webapi 8 + reason-react 9 + server-reason-react.url_js) 10 + (preprocess 11 + (pps 12 + server-reason-react.browser_ppx -js 13 + melange.ppx 14 + melange-json.ppx 15 + reason-react-ppx))) 16 + 17 + (include_subdirs qualified) 18 + 19 + (copy_files# "../src/components/*.mlx") 20 + (copy_files# "../src/icons/*.mlx") 21 + (copy_files# "../src/templates/*.mlx")
-80
frontend/lib/client.ml
··· 1 - module DOM = Webapi.Dom 2 - module Location = DOM.Location 3 - module History = DOM.History 4 - module ReadableStream = Webapi.ReadableStream 5 - 6 - external setNavigate : DOM.Window.t -> (string -> unit) -> unit = "__navigate" 7 - [@@mel.scope "window"] [@@mel.set] 8 - 9 - external readable_stream : ReadableStream.t 10 - = "window.srr_stream.readable_stream" 11 - 12 - let fetchApp url = 13 - let obj = [%mel.obj {accept= "application/react.component"}] in 14 - let headers = Fetch.HeadersInit.make obj in 15 - Fetch.fetchWithInit url 16 - (Fetch.RequestInit.make ~method_:Fetch.Get ~headers ()) 17 - 18 - let navigate ~setLayout search = 19 - let location = DOM.Window.location DOM.window in 20 - let origin = Location.origin location in 21 - let pathname = Location.pathname location in 22 - let currentSearch = Location.search location in 23 - let currentParams = URL.SearchParams.makeExn currentSearch in 24 - let newSearchParams = Js.Dict.empty () in 25 - URL.SearchParams.forEach currentParams (fun value key -> 26 - Js.Dict.set newSearchParams key value ) ; 27 - let newParams = URL.SearchParams.makeExn search in 28 - URL.SearchParams.forEach newParams (fun value key -> 29 - Js.Dict.set newSearchParams key value ) ; 30 - let finalSearch = 31 - newSearchParams |> Js.Dict.entries |> URL.SearchParams.makeWithArray 32 - |> URL.SearchParams.toString 33 - in 34 - if currentSearch = "?" ^ finalSearch then () 35 - else 36 - let domain = URL.makeExn (origin ^ pathname) in 37 - let finalURL = 38 - URL.setSearch domain (URL.SearchParams.makeExn finalSearch) 39 - in 40 - let response = fetchApp (URL.toString finalURL) in 41 - ReactServerDOMEsbuild.createFromFetch response 42 - |> Js.Promise.then_ (fun element -> 43 - History.pushState 44 - (History.state DOM.history) 45 - "" (URL.toString finalURL) DOM.history ; 46 - setLayout (fun _ -> element) ; 47 - Js.Promise.resolve () ) 48 - |> ignore 49 - 50 - module App_from_readable_stream = struct 51 - let initial = ReactServerDOMEsbuild.createFromReadableStream readable_stream 52 - 53 - let[@react.component] make () = 54 - let initialElement = React.Experimental.usePromise initial in 55 - let layout, setLayout = React.useState (fun () -> initialElement) in 56 - setNavigate DOM.window (navigate ~setLayout) ; 57 - let fallback error = 58 - Js.log error ; 59 - React.createElement 60 - (ReactDOM.stringToComponent "h1") 61 - (ReactDOM.domProps ~children:(React.string "Something went wrong!") ()) 62 - in 63 - React.createElement ReasonReactErrorBoundary.make 64 - (ReasonReactErrorBoundary.makeProps ~fallback ~children:layout ()) 65 - end 66 - 67 - let () = 68 - let document = DOM.Document.asHtmlDocument DOM.document in 69 - let body = Option.bind document DOM.HtmlDocument.body in 70 - match body with 71 - | Some element -> 72 - let transition () = 73 - ReactDOM.Client.hydrateRoot element 74 - (React.createElement App_from_readable_stream.make 75 - (App_from_readable_stream.makeProps ()) ) 76 - |> ignore 77 - in 78 - React.startTransition transition 79 - | None -> 80 - Js.log "Root element not found"
+8 -2
frontend/lib/components/Button.mlx frontend/src/components/Button.mlx
··· 28 28 disabled:bg-mana-40" 29 29 30 30 let[@react.component] make ?id ?name ?(kind = `Primary) ?(type_ = "button") 31 - ?onClick ?value ?(className = "") ~children () = 31 + ?formMethod ?onClick ?value ?(className = "") ~children () = 32 32 <button 33 - ?id ?name type_ ?onClick ?value className=(classes kind ^ " " ^ className)> 33 + ?id 34 + ?name 35 + type_ 36 + ?formMethod 37 + ?onClick 38 + ?value 39 + className=(classes kind ^ " " ^ className)> 34 40 children 35 41 </button>
frontend/lib/components/Input.mlx frontend/src/components/Input.mlx
-21
frontend/lib/dune
··· 1 - (library 2 - (name frontend) 3 - (modules :standard \ client) 4 - (libraries server-reason-react.react) 5 - (preprocess 6 - (pps server-reason-react.melange_ppx server-reason-react.ppx))) 7 - 8 - (melange.emit 9 - (target app) 10 - (modules client) 11 - (module_systems es6) 12 - (libraries 13 - melange.js 14 - reason-react 15 - react_server_dom_esbuild 16 - server-reason-react.url_js 17 - melange-webapi) 18 - (preprocess 19 - (pps melange.ppx reason-react-ppx))) 20 - 21 - (include_subdirs qualified)
frontend/lib/icons/CircleAlert.mlx frontend/src/icons/CircleAlertIcon.mlx
-66
frontend/lib/templates/Authorize.mlx
··· 1 - open Components 2 - open React 3 - 4 - let cimd_suffix_len = String.length "/oauth-client-metadata.json" 5 - 6 - let[@react.component] make ~client_url ?client_name ~handle ~scopes ~code 7 - ~request_uri ~csrf_token () = 8 - let host, path = client_url in 9 - let rendered_name = 10 - match client_name with 11 - | Some client_name -> 12 - <span className="text-mana-100 font-serif"> 13 - (string client_name) 14 - <span className="font-sans">(string (" (" ^ host ^ ")"))</span> 15 - </span> 16 - | None when String.length path = 0 -> 17 - <span className="text-mana-100 font-serif">(string host)</span> 18 - | None -> 19 - <span className="text-mana-100 font-serif"> 20 - (string host) <span className="text-mana-40">(string path)</span> 21 - </span> 22 - in 23 - let rendered_handle = 24 - <span className="text-mana-100 font-serif">(string @@ "@" ^ handle)</span> 25 - in 26 - <Layout title=("Authorize " ^ host)> 27 - <main className="w-full h-auto max-w-lg px-4 sm:px-0"> 28 - <h1 className="text-2xl font-serif text-mana-200 mb-2"> 29 - (string ("authorizing " ^ host)) 30 - </h1> 31 - <p className="w-full text-mist-100"> 32 - (string "You’re signing into ") 33 - rendered_name 34 - (string " as ") 35 - rendered_handle 36 - (string " and granting it the following permissions:") 37 - </p> 38 - <ul className="w-full text-mist-100 list-disc ml-8 mt-2 space-y-1"> 39 - ( List.map (fun scope -> <li>(string scope)</li>) scopes 40 - |> Array.of_list |> array ) 41 - </ul> 42 - <form 43 - method_="post" 44 - className="w-full flex flex-row items-center justify-between mt-6"> 45 - <input type_="hidden" name="dream.csrf" value=csrf_token /> 46 - <input type_="hidden" name="code" value=code /> 47 - <input type_="hidden" name="request_uri" value=request_uri /> 48 - <Button 49 - kind=`Secondary 50 - type_="submit" 51 - name="action" 52 - value="deny" 53 - className="grow basis-1/3 min-w-0"> 54 - (string "cancel") 55 - </Button> 56 - <Button 57 - kind=`Primary 58 - type_="submit" 59 - name="action" 60 - value="allow" 61 - className="grow basis-2/3 min-w-0 max-w-2xs"> 62 - (string "authorize") 63 - </Button> 64 - </form> 65 - </main> 66 - </Layout>
-16
frontend/lib/templates/Layout.mlx
··· 1 - open React 2 - 3 - let[@react.component] make ?(title = "Pegasus") ~children () = 4 - <html lang="en"> 5 - <head> 6 - <meta charSet="utf-8" /> 7 - <meta name="viewport" content="width=device-width, initial-scale=1" /> 8 - <link rel="stylesheet" href="/public/index.css" /> 9 - <title>(string title)</title> 10 - </head> 11 - <body 12 - className="bg-feather-100 font-sans font-normal text-base \ 13 - tracking-normal flex items-center justify-center min-h-screen"> 14 - children 15 - </body> 16 - </html>
-37
frontend/lib/templates/Login.mlx
··· 1 - open Components 2 - open React 3 - 4 - let[@react.component] make ~redirect_url ?error ~csrf_token () = 5 - <Layout title="Sign In"> 6 - <main className="w-full h-auto max-w-xs px-4 sm:px-0"> 7 - <h1 className="text-2xl font-serif text-mana-200 mb-2"> 8 - (string "sign in") 9 - </h1> 10 - <span className="w-full text-balance text-mist-100"> 11 - (string "Enter your handle, email address, or DID, and your password.") 12 - </span> 13 - <form method_="post" className="w-full flex flex-col mt-4 mb-2 gap-y-2"> 14 - <input type_="hidden" name="dream.csrf" value=csrf_token /> 15 - <Input sr_only=true name="identifier" type_="text" label="identifier" /> 16 - <Input sr_only=true name="password" type_="password" label="password" /> 17 - <input type_="hidden" name="redirect_url" value=redirect_url /> 18 - ( match error with 19 - | Some error -> 20 - <span className="inline-flex items-center text-phoenix-100 text-sm"> 21 - <Icons.CircleAlert className="w-4 h-4 mr-2" /> (string error) 22 - </span> 23 - | None -> 24 - null ) 25 - <Button type_="submit" className="mt-2">(string "sign in")</Button> 26 - </form> 27 - <span className="text-sm text-mist-100"> 28 - (string "Or ") 29 - <a 30 - href="/account/signup" 31 - className="text-mana-100 underline hover:text-mana-200"> 32 - (string "create an account") 33 - </a> 34 - (string ".") 35 - </span> 36 - </main> 37 - </Layout>
-350
frontend/lib/vendor/react-server-dom-esbuild/ReactServerDOMEsbuild.ml
··· 1 - [%%mel.raw 2 - {| 3 - /* 4 - * This file is a bundler integration between react (react-client/flight), esbuild and server-reason-react. 5 - * 6 - * Similar resources: 7 - * - **react-server-dom-webpack**: https://github.com/facebook/react/blob/5c56b873efb300b4d1afc4ba6f16acf17e4e5800/packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js#L156-L194 8 - * - **react-server-dom-parcel**: https://github.com/facebook/react/pull/31725 9 - */ 10 - 11 - const ReactClientFlight = require("@pedrobslisboa/react-client/flight"); 12 - 13 - const isDebug = false; 14 - 15 - const debug = (...args) => { 16 - if (isDebug && process.env.NODE_ENV === "development") { 17 - console.log(...args); 18 - } 19 - }; 20 - 21 - const ReactFlightClientStreamConfigWeb = { 22 - createStringDecoder() { 23 - return new TextDecoder(); 24 - }, 25 - 26 - readPartialStringChunk(decoder, buffer) { 27 - return decoder.decode(buffer, { stream: true }); 28 - }, 29 - 30 - readFinalStringChunk(decoder, buffer) { 31 - return decoder.decode(buffer); 32 - }, 33 - }; 34 - 35 - const badgeFormat = "%c%s%c "; 36 - 37 - // Same badge styling as DevTools. 38 - const badgeStyle = 39 - // We use a fixed background if light-dark is not supported, otherwise 40 - // we use a transparent background. 41 - "background: #e6e6e6;" + 42 - "background: light-dark(rgba(0,0,0,0.1), rgba(255,255,255,0.25));" + 43 - "color: #000000;" + 44 - "color: light-dark(#000000, #ffffff);" + 45 - "border-radius: 2px"; 46 - 47 - const resetStyle = ""; 48 - const pad = " "; 49 - 50 - const bind = Function.prototype.bind; 51 - 52 - const ReactClientConsoleConfigBrowser = { 53 - bindToConsole(methodName, args, badgeName) { 54 - let offset = 0; 55 - switch (methodName) { 56 - case "dir": 57 - case "dirxml": 58 - case "groupEnd": 59 - case "table": { 60 - // These methods cannot be colorized because they don't take a formatting string. 61 - return bind.apply(console[methodName], [console].concat(args)); 62 - } 63 - case "assert": { 64 - // assert takes formatting options as the second argument. 65 - offset = 1; 66 - } 67 - } 68 - 69 - const newArgs = args.slice(0); 70 - if (typeof newArgs[offset] === "string") { 71 - newArgs.splice( 72 - offset, 73 - 1, 74 - badgeFormat + newArgs[offset], 75 - badgeStyle, 76 - pad + badgeName + pad, 77 - resetStyle 78 - ); 79 - } else { 80 - newArgs.splice( 81 - offset, 82 - 0, 83 - badgeFormat, 84 - badgeStyle, 85 - pad + badgeName + pad, 86 - resetStyle 87 - ); 88 - } 89 - 90 - // The "this" binding in the "bind"; 91 - newArgs.unshift(console); 92 - 93 - return bind.apply(console[methodName], newArgs); 94 - }, 95 - }; 96 - 97 - const ID = 0; 98 - const NAME = 1; 99 - const BUNDLES = 2; 100 - 101 - const ReactFlightClientConfigBundlerEsbuild = { 102 - prepareDestinationForModule(moduleLoading, nonce, metadata) { 103 - debug("prepareDestinationForModule", moduleLoading, nonce, metadata); 104 - return; 105 - }, 106 - 107 - resolveClientReference(bundlerConfig, metadata) { 108 - debug("resolveClientReference", bundlerConfig, metadata); 109 - // Reference is already resolved during the build 110 - return { 111 - type: "ClientComponent", 112 - id: metadata[ID], 113 - name: metadata[NAME], 114 - bundles: metadata[BUNDLES], 115 - }; 116 - }, 117 - 118 - resolveServerReference(bundlerConfig, ref) { 119 - debug("resolveServerReference", bundlerConfig, ref); 120 - 121 - return { 122 - type: "ServerFunction", 123 - id: ref, 124 - }; 125 - }, 126 - 127 - preloadModule(metadata) { 128 - debug("preloadModule", metadata); 129 - /* TODO: Does it make sense to preload a module in esbuild? */ 130 - return undefined; 131 - }, 132 - 133 - requireModule(metadata) { 134 - const getModule = (type, id) => { 135 - switch (type) { 136 - case "ServerFunction": 137 - const fn = window.__server_functions_manifest_map[id]; 138 - 139 - return fn; 140 - case "ClientComponent": 141 - const component = window.__client_manifest_map[id]; 142 - 143 - return component 144 - } 145 - } 146 - 147 - const module = getModule(metadata.type, metadata.id); 148 - if (!module) { 149 - throw new Error(`Could not find module of type ${metadata.type} with id: ${metadata.id}`); 150 - } 151 - 152 - return module 153 - }, 154 - }; 155 - 156 - /* TODO: Can we use the real thing, instead of mocks/vendored code here? */ 157 - const ReactServerDOMEsbuildConfig = { 158 - ...ReactFlightClientStreamConfigWeb, 159 - ...ReactClientConsoleConfigBrowser, 160 - ...ReactFlightClientConfigBundlerEsbuild, 161 - rendererVersion: "19.0.0", 162 - rendererPackageName: "react-server-dom-esbuild", 163 - usedWithSSR: true, 164 - }; 165 - 166 - const { 167 - createResponse, 168 - createServerReference: createServerReferenceImpl, 169 - processReply, 170 - getRoot, 171 - reportGlobalError, 172 - processBinaryChunk, 173 - createStreamState, 174 - close, 175 - } = ReactClientFlight(ReactServerDOMEsbuildConfig); 176 - 177 - function startReadingFromStream(response, stream) { 178 - const streamState = createStreamState(); 179 - const reader = stream.getReader(); 180 - function progress({ 181 - done, 182 - value, 183 - }) { 184 - if (done) { 185 - close(response); 186 - return; 187 - } 188 - const buffer = value; 189 - processBinaryChunk(response, streamState, buffer); 190 - return reader.read().then(progress).catch(error); 191 - } 192 - function error(e) { 193 - reportGlobalError(response, e); 194 - } 195 - reader.read().then(progress).catch(error); 196 - } 197 - 198 - function callCurrentServerCallback(callServer) { 199 - return function (id, args) { 200 - if (!callServer) { 201 - throw new Error( 202 - "No server callback has been registered. Call setServerCallback to register one." 203 - ); 204 - } 205 - return callServer(id, args); 206 - }; 207 - } 208 - 209 - function createFromReadableStream(stream, options) { 210 - const response = createResponseFromOptions(options); 211 - startReadingFromStream(response, stream); 212 - return getRoot(response); 213 - } 214 - 215 - function createResponseFromOptions(options) { 216 - let response = createResponse( 217 - null, // bundlerConfig 218 - {}, // serverFunctionsConfig, this is the manifest that can contain configs related to server functions. It requires it to not be null, to run resolveServerReference 219 - null, // moduleLoading 220 - callCurrentServerCallback(options ? options.callServer : undefined), 221 - undefined, // encodeFormAction 222 - undefined, // nonce 223 - options && options.temporaryReferences 224 - ? options.temporaryReferences 225 - : undefined, 226 - undefined, // TODO: findSourceMapUrl 227 - false /* __DEV__ ? (options ? options.replayConsoleLogs !== false : true) */, 228 - undefined /* __DEV__ && options && options.environmentName 229 - ? options.environmentName 230 - : undefined */ 231 - ); 232 - 233 - return response; 234 - } 235 - 236 - function createFromFetch(promise, options) { 237 - const response = createResponseFromOptions(options); 238 - promise.then( 239 - function (r) { 240 - startReadingFromStream(response, r.body); 241 - }, 242 - function (e) { 243 - reportGlobalError(response, e); 244 - } 245 - ); 246 - return getRoot(response); 247 - } 248 - 249 - const createServerReference = createServerReferenceImpl; 250 - 251 - const encodeReply = ( 252 - value, 253 - options = { temporaryReferences: undefined, signal: undefined } 254 - ) => { 255 - return new Promise((resolve, reject) => { 256 - const abort = processReply( 257 - value, 258 - "", 259 - options && options.temporaryReferences 260 - ? options.temporaryReferences 261 - : undefined, 262 - resolve, 263 - reject 264 - ); 265 - if (options && options.signal) { 266 - const signal = options.signal; 267 - if (signal.aborted) { 268 - abort(signal.reason); 269 - } else { 270 - const listener = () => { 271 - abort(signal.reason); 272 - signal.removeEventListener("abort", listener); 273 - }; 274 - signal.addEventListener("abort", listener); 275 - } 276 - } 277 - }); 278 - }; 279 - 280 - module.exports = { 281 - createFromReadableStream, 282 - createFromFetch, 283 - createServerReference, 284 - encodeReply, 285 - } 286 - |}] 287 - 288 - type arg 289 - 290 - type callServer = string -> arg list -> React.element Js.Promise.t 291 - 292 - type options = {callServer: callServer} 293 - 294 - external createFromReadableStreamImpl : 295 - Webapi.ReadableStream.t 296 - -> ?options:options 297 - -> unit 298 - -> React.element Js.Promise.t = "createFromReadableStream" 299 - 300 - external createFromFetchImpl : 301 - Fetch.response Js.Promise.t 302 - -> ?options:options 303 - -> unit 304 - -> React.element Js.Promise.t = "createFromFetch" 305 - 306 - external createServerReferenceImpl : 307 - string 308 - -> callServer 309 - -> 'encodeFormActionCallback option 310 - -> 'findSourceMapURLCallback option 311 - -> string option 312 - -> 'action = "createServerReference" 313 - 314 - external encodeReply : 'arg list -> string Js.Promise.t = "encodeReply" 315 - 316 - let callServerRef = (ref None : callServer option ref) 317 - 318 - let setCallServer callServer = callServerRef := Some callServer 319 - 320 - let getCallServer () = !callServerRef 321 - 322 - let createFromReadableStream ?callServer stream : React.element Js.Promise.t = 323 - match callServer with 324 - | Some callServer -> 325 - setCallServer callServer ; 326 - createFromReadableStreamImpl stream ~options:{callServer} () 327 - | None -> 328 - createFromReadableStreamImpl stream () 329 - 330 - let createFromFetch ?callServer promise = 331 - match callServer with 332 - | Some callServer -> 333 - setCallServer callServer ; 334 - createFromFetchImpl promise ~options:{callServer} () 335 - | None -> 336 - createFromFetchImpl promise () 337 - 338 - let createServerReference serverReferenceId = 339 - let callServer = 340 - match getCallServer () with 341 - | Some callServer -> 342 - callServer 343 - | None -> 344 - raise 345 - (Invalid_argument 346 - "No callServer has been set, you are trying to create a server \ 347 - function without passing callServer to createFromFetch or \ 348 - createFromReadableStream" ) 349 - in 350 - createServerReferenceImpl serverReferenceId callServer None None None
-9
frontend/lib/vendor/react-server-dom-esbuild/dune
··· 1 - (library 2 - (name react_server_dom_esbuild) 3 - (modes melange) 4 - (wrapped false) 5 - (libraries reason-react melange-webapi melange-fetch) 6 - (preprocess 7 - (pps melange.ppx))) 8 - 9 - (include_subdirs qualified)
+16
frontend/src/dune
··· 1 + (include_subdirs unqualified) 2 + 3 + (library 4 + (name frontend) 5 + (modes native) 6 + (libraries 7 + server-reason-react.react 8 + server-reason-react.reactDom 9 + dream 10 + melange-json-native) 11 + (preprocess 12 + (pps 13 + melange-json-native.ppx 14 + server-reason-react.melange_ppx 15 + server-reason-react.ppx 16 + server-reason-react.browser_ppx)))
+17
frontend/src/templates/Layout.mlx
··· 1 + open React 2 + 3 + let[@react.component] make ?(title = "Pegasus") ?(children = null) () = 4 + <html lang="en"> 5 + <head> 6 + <meta charSet="utf-8" /> 7 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 8 + <link rel="stylesheet" href="/public/index.css" /> 9 + <title>(string title)</title> 10 + </head> 11 + <body 12 + className="bg-feather-100 font-sans font-normal text-base tracking-normal"> 13 + <div id="root" className="flex items-center justify-center min-h-screen"> 14 + children 15 + </div> 16 + </body> 17 + </html>
+44
frontend/src/templates/LoginPage.mlx
··· 1 + open Melange_json.Primitives 2 + open React 3 + 4 + type props = 5 + { redirect_url: string 6 + ; csrf_token: string 7 + ; error: string option [@default None] } 8 + [@@deriving json] 9 + 10 + let[@react.component] make ~props:({redirect_url; csrf_token; error} : props) () 11 + = 12 + <main className="w-full h-auto max-w-xs px-4 sm:px-0"> 13 + <h1 className="text-2xl font-serif text-mana-200 mb-2"> 14 + (string "sign in") 15 + </h1> 16 + <span className="w-full text-balance text-mist-100"> 17 + (string "Enter your handle, email address, or DID, and your password.") 18 + </span> 19 + <form className="w-full flex flex-col mt-4 mb-2 gap-y-2"> 20 + <input type_="hidden" name="dream.csrf" value=csrf_token /> 21 + <Input sr_only=true name="identifier" type_="text" label="identifier" /> 22 + <Input sr_only=true name="password" type_="password" label="password" /> 23 + <input type_="hidden" name="redirect_url" value=redirect_url /> 24 + ( match error with 25 + | Some error -> 26 + <span className="inline-flex items-center text-phoenix-100 text-sm"> 27 + <CircleAlertIcon className="w-4 h-4 mr-2" /> (string error) 28 + </span> 29 + | None -> 30 + null ) 31 + <Button type_="submit" formMethod="post" className="mt-2"> 32 + (string "sign in") 33 + </Button> 34 + </form> 35 + <span className="text-sm text-mist-100"> 36 + (string "Or ") 37 + <a 38 + href="/account/signup" 39 + className="text-mana-100 underline hover:text-mana-200"> 40 + (string "create an account") 41 + </a> 42 + (string ".") 43 + </span> 44 + </main>
+76
frontend/src/templates/OauthAuthorizePage.mlx
··· 1 + open Melange_json.Primitives 2 + open React 3 + 4 + let cimd_suffix_len = String.length "/oauth-client-metadata.json" 5 + 6 + type props = 7 + { client_url: string * string (* (host, path) *) 8 + ; client_name: string option [@default None] 9 + ; handle: string 10 + ; scopes: string list 11 + ; code: string 12 + ; request_uri: string 13 + ; csrf_token: string } 14 + [@@deriving json] 15 + 16 + let[@react.component] make 17 + ~props: 18 + ({client_url; client_name; handle; scopes; code; request_uri; csrf_token} : 19 + props ) () = 20 + let host, path = client_url in 21 + let rendered_name = 22 + match client_name with 23 + | Some client_name -> 24 + <span className="text-mana-100 font-serif"> 25 + (string client_name) 26 + <span className="font-sans">(string (" (" ^ host ^ ")"))</span> 27 + </span> 28 + | None when String.length path = 0 -> 29 + <span className="text-mana-100 font-serif">(string host)</span> 30 + | None -> 31 + <span className="text-mana-100 font-serif"> 32 + (string host) <span className="text-mana-40">(string path)</span> 33 + </span> 34 + in 35 + let rendered_handle = 36 + <span className="text-mana-100 font-serif">(string @@ "@" ^ handle)</span> 37 + in 38 + <main className="w-full h-auto max-w-lg px-4 sm:px-0"> 39 + <h1 className="text-2xl font-serif text-mana-200 mb-2"> 40 + (string ("authorizing " ^ host)) 41 + </h1> 42 + <p className="w-full text-mist-100"> 43 + (string "You're signing into ") 44 + rendered_name 45 + (string " as ") 46 + rendered_handle 47 + (string " and granting it the following permissions:") 48 + </p> 49 + <ul className="w-full text-mist-100 list-disc ml-8 mt-2 space-y-1"> 50 + ( List.map (fun scope -> <li>(string scope)</li>) scopes 51 + |> Array.of_list |> array ) 52 + </ul> 53 + <form className="w-full flex flex-row items-center justify-between mt-6"> 54 + <input type_="hidden" name="dream.csrf" value=csrf_token /> 55 + <input type_="hidden" name="code" value=code /> 56 + <input type_="hidden" name="request_uri" value=request_uri /> 57 + <Button 58 + kind=`Secondary 59 + type_="submit" 60 + formMethod="post" 61 + name="action" 62 + value="deny" 63 + className="grow basis-1/3 min-w-0"> 64 + (string "cancel") 65 + </Button> 66 + <Button 67 + kind=`Primary 68 + type_="submit" 69 + formMethod="post" 70 + name="action" 71 + value="allow" 72 + className="grow basis-2/3 min-w-0 max-w-2xs"> 73 + (string "authorize") 74 + </Button> 75 + </form> 76 + </main>
+21
package.json
··· 1 + { 2 + "name": "pegasus", 3 + "version": "1.0.0", 4 + "description": "", 5 + "main": "index.js", 6 + "scripts": { 7 + "test": "echo \"Error: no test specified\" && exit 1" 8 + }, 9 + "keywords": [], 10 + "author": "", 11 + "license": "ISC", 12 + "dependencies": { 13 + "@pedrobslisboa/react-client": "^19.1.0", 14 + "react": "^19.2.0", 15 + "react-dom": "^19.2.0", 16 + "vite": "^7.2.2" 17 + }, 18 + "devDependencies": { 19 + "@rollup/plugin-node-resolve": "^16.0.3" 20 + } 21 + }
+12 -19
pegasus/lib/api/account_/login.ml
··· 7 7 else "/account" 8 8 in 9 9 let csrf_token = Dream.csrf_token ctx.req in 10 - let html = 11 - ReactDOM.renderToStaticMarkup 12 - (Frontend.Templates.Login.make ~redirect_url ~csrf_token ()) 13 - in 14 - Dream.html html ) 10 + Util.render_html ~title:"Login" 11 + (module Frontend.LoginPage) 12 + ~props:{redirect_url; csrf_token; error= None} ) 15 13 16 14 let post_handler = 17 15 Xrpc.handler (fun ctx -> ··· 29 27 in 30 28 match actor with 31 29 | None -> 32 - let html = 33 - ReactDOM.renderToStaticMarkup 34 - (Frontend.Templates.Login.make ~redirect_url 35 - ~error:"Invalid username or password. Please try again." 36 - ~csrf_token () ) 37 - in 38 - Dream.html ~status:`Unauthorized html 30 + let error = "Invalid username or password. Please try again." in 31 + Util.render_html ~status:`Unauthorized ~title:"Login" 32 + (module Frontend.LoginPage) 33 + ~props:{redirect_url; csrf_token; error= Some error} 39 34 | Some {did; _} -> 40 35 let%lwt () = Dream.invalidate_session ctx.req in 41 36 let%lwt () = Dream.set_session_field ctx.req "did" did in 42 37 Dream.redirect ctx.req redirect_url ) 43 38 | _ -> 44 - let html = 45 - ReactDOM.renderToStaticMarkup 46 - (Frontend.Templates.Login.make ~redirect_url:"/account" 47 - ~error:"Invalid credentials provided. Please try again." 48 - ~csrf_token () ) 49 - in 50 - Dream.html ~status:`Unauthorized html ) 39 + let redirect_url = "/account" in 40 + let error = "Something went wrong, go back and try again." in 41 + Util.render_html ~status:`Unauthorized ~title:"Login" 42 + (module Frontend.LoginPage) 43 + ~props:{redirect_url; csrf_token; error= Some error} )
+11 -11
pegasus/lib/api/oauth_/authorize.ml
··· 89 89 , Uri.path client_id_uri ) 90 90 in 91 91 let client_url = (host, path) in 92 - let client_name = 93 - Option.value metadata.client_name 94 - ~default:(host ^ "/" ^ path) 95 - in 96 - let html = 97 - ReactDOM.renderToStaticMarkup 98 - (Frontend.Templates.Authorize.make ~client_name 99 - ~client_url ~handle ~scopes ~code ~request_uri 100 - ~csrf_token () ) 101 - in 102 - Dream.html html ) ) ) ) 92 + let client_name = metadata.client_name in 93 + Util.render_html ~title:("Authorizing " ^ host) 94 + (module Frontend.OauthAuthorizePage) 95 + ~props: 96 + { client_url 97 + ; client_name 98 + ; handle 99 + ; scopes 100 + ; code 101 + ; request_uri 102 + ; csrf_token } ) ) ) ) 103 103 104 104 let post_handler = 105 105 Xrpc.handler (fun ctx ->
-2
pegasus/lib/api/oauth_/par.ml
··· 1 1 open Oauth 2 2 open Oauth.Types 3 3 4 - let options_handler = Xrpc.handler (fun _ -> Dream.empty `No_Content) 5 - 6 4 let post_handler = 7 5 Xrpc.handler ~auth:DPoP (fun ctx -> 8 6 let proof = Auth.get_dpop_proof_exn ctx.auth in
-2
pegasus/lib/api/oauth_/token.ml
··· 1 1 open Oauth 2 2 3 - let options_handler = Xrpc.handler (fun _ -> Dream.empty `No_Content) 4 - 5 3 let post_handler = 6 4 Xrpc.handler ~auth:DPoP (fun ctx -> 7 5 let%lwt req = Xrpc.parse_body ctx.req Types.token_request_of_yojson in
-57
pegasus/lib/rsc.ml
··· 1 - let debug = Sys.getenv_opt "DEMO_ENV" == Some "development" 2 - 3 - let is_react_component_header str = 4 - String.equal str "application/react.component" 5 - 6 - let stream_model ~location app = 7 - Dream.stream 8 - ~headers: 9 - [ ("Content-Type", "application/react.component") 10 - ; ("X-Content-Type-Options", "nosniff") 11 - ; ("X-Location", location) ] 12 - (fun stream -> 13 - [%lwt 14 - let () = 15 - ReactServerDOM.render_model ~debug 16 - ~subscribe:(fun chunk -> 17 - if debug then (Dream.log "Chunk" ; Dream.log "%s" chunk) ; 18 - [%lwt 19 - let () = Dream.write stream chunk in 20 - Dream.flush stream] ) 21 - app 22 - in 23 - Dream.flush stream] ) 24 - 25 - let stream_html ?(skipRoot = false) ?bootstrapScriptContent 26 - ?(bootstrapScripts = []) ?(bootstrapModules = []) app = 27 - Dream.stream 28 - ~headers:[("Content-Type", "text/html")] 29 - (fun stream -> 30 - [%lwt 31 - let html, subscribe = 32 - ReactServerDOM.render_html ~skipRoot ?bootstrapScriptContent 33 - ~bootstrapScripts ~bootstrapModules ~debug app 34 - in 35 - [%lwt 36 - let () = Dream.write stream html in 37 - [%lwt 38 - let () = Dream.flush stream in 39 - [%lwt 40 - let () = 41 - subscribe (fun chunk -> 42 - if debug then (Dream.log "Chunk" ; Dream.log "%s" chunk) ; 43 - [%lwt 44 - let () = Dream.write stream chunk in 45 - Dream.flush stream] ) 46 - in 47 - Dream.flush stream]]]] ) 48 - 49 - let createFromRequest ?(disableSSR = false) ?(layout = fun children -> children) 50 - ?(bootstrapModules = []) ?(bootstrapScripts = []) 51 - ?(bootstrapScriptContent = "") element request = 52 - match Dream.header request "accept" with 53 - | Some accept when is_react_component_header accept -> 54 - stream_model ~location:(Dream.target request) (React.Model.Element element) 55 - | _ -> 56 - stream_html ~skipRoot:disableSSR ~bootstrapScriptContent ~bootstrapScripts 57 - ~bootstrapModules (layout element)
+39
pegasus/lib/util.ml
··· 364 364 http_get uri ~max_redirects:(max_redirects - 1) 365 365 366 366 let copy_query req = Dream.all_queries req |> List.map (fun (k, v) -> (k, [v])) 367 + 368 + module type Template = sig 369 + type props 370 + 371 + val props_of_json : Yojson.Basic.t -> props 372 + 373 + val props_to_json : props -> Yojson.Basic.t 374 + 375 + val make : ?key:string -> props:props -> unit -> React.element 376 + end 377 + 378 + let render_html ?status ?title (type props) 379 + (template : (module Template with type props = props)) ~props = 380 + let module Template = (val template : Template with type props = props) in 381 + let props_json = Template.props_to_json props |> Yojson.Basic.to_string in 382 + let page_data = Printf.sprintf "window.__PAGE__ = {props: %s};" props_json in 383 + let app = Template.make ~props () in 384 + let page = Frontend.Layout.make ?title ~children:app () in 385 + Dream.stream ?status 386 + ~headers:[("Content-Type", "text/html")] 387 + (fun stream -> 388 + [%lwt 389 + let html, subscribe = 390 + ReactServerDOM.render_html ~skipRoot:false 391 + ~bootstrapScriptContent:page_data 392 + ~bootstrapScripts:["/public/client.js"] page 393 + in 394 + [%lwt 395 + let () = Dream.write stream html in 396 + [%lwt 397 + let () = Dream.flush stream in 398 + [%lwt 399 + let () = 400 + subscribe (fun chunk -> 401 + [%lwt 402 + let () = Dream.write stream chunk in 403 + Dream.flush stream] ) 404 + in 405 + Dream.flush stream]]]] )
+758
pnpm-lock.yaml
··· 1 + lockfileVersion: '9.0' 2 + 3 + settings: 4 + autoInstallPeers: true 5 + excludeLinksFromLockfile: false 6 + 7 + importers: 8 + 9 + .: 10 + dependencies: 11 + '@pedrobslisboa/react-client': 12 + specifier: ^19.1.0 13 + version: 19.1.0(react@19.2.0) 14 + react: 15 + specifier: ^19.2.0 16 + version: 19.2.0 17 + react-dom: 18 + specifier: ^19.2.0 19 + version: 19.2.0(react@19.2.0) 20 + vite: 21 + specifier: ^7.2.2 22 + version: 7.2.2 23 + devDependencies: 24 + '@rollup/plugin-node-resolve': 25 + specifier: ^16.0.3 26 + version: 16.0.3(rollup@4.53.2) 27 + 28 + packages: 29 + 30 + '@esbuild/aix-ppc64@0.25.12': 31 + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} 32 + engines: {node: '>=18'} 33 + cpu: [ppc64] 34 + os: [aix] 35 + 36 + '@esbuild/android-arm64@0.25.12': 37 + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} 38 + engines: {node: '>=18'} 39 + cpu: [arm64] 40 + os: [android] 41 + 42 + '@esbuild/android-arm@0.25.12': 43 + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} 44 + engines: {node: '>=18'} 45 + cpu: [arm] 46 + os: [android] 47 + 48 + '@esbuild/android-x64@0.25.12': 49 + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} 50 + engines: {node: '>=18'} 51 + cpu: [x64] 52 + os: [android] 53 + 54 + '@esbuild/darwin-arm64@0.25.12': 55 + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} 56 + engines: {node: '>=18'} 57 + cpu: [arm64] 58 + os: [darwin] 59 + 60 + '@esbuild/darwin-x64@0.25.12': 61 + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} 62 + engines: {node: '>=18'} 63 + cpu: [x64] 64 + os: [darwin] 65 + 66 + '@esbuild/freebsd-arm64@0.25.12': 67 + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} 68 + engines: {node: '>=18'} 69 + cpu: [arm64] 70 + os: [freebsd] 71 + 72 + '@esbuild/freebsd-x64@0.25.12': 73 + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} 74 + engines: {node: '>=18'} 75 + cpu: [x64] 76 + os: [freebsd] 77 + 78 + '@esbuild/linux-arm64@0.25.12': 79 + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} 80 + engines: {node: '>=18'} 81 + cpu: [arm64] 82 + os: [linux] 83 + 84 + '@esbuild/linux-arm@0.25.12': 85 + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} 86 + engines: {node: '>=18'} 87 + cpu: [arm] 88 + os: [linux] 89 + 90 + '@esbuild/linux-ia32@0.25.12': 91 + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} 92 + engines: {node: '>=18'} 93 + cpu: [ia32] 94 + os: [linux] 95 + 96 + '@esbuild/linux-loong64@0.25.12': 97 + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} 98 + engines: {node: '>=18'} 99 + cpu: [loong64] 100 + os: [linux] 101 + 102 + '@esbuild/linux-mips64el@0.25.12': 103 + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} 104 + engines: {node: '>=18'} 105 + cpu: [mips64el] 106 + os: [linux] 107 + 108 + '@esbuild/linux-ppc64@0.25.12': 109 + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} 110 + engines: {node: '>=18'} 111 + cpu: [ppc64] 112 + os: [linux] 113 + 114 + '@esbuild/linux-riscv64@0.25.12': 115 + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} 116 + engines: {node: '>=18'} 117 + cpu: [riscv64] 118 + os: [linux] 119 + 120 + '@esbuild/linux-s390x@0.25.12': 121 + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} 122 + engines: {node: '>=18'} 123 + cpu: [s390x] 124 + os: [linux] 125 + 126 + '@esbuild/linux-x64@0.25.12': 127 + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} 128 + engines: {node: '>=18'} 129 + cpu: [x64] 130 + os: [linux] 131 + 132 + '@esbuild/netbsd-arm64@0.25.12': 133 + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} 134 + engines: {node: '>=18'} 135 + cpu: [arm64] 136 + os: [netbsd] 137 + 138 + '@esbuild/netbsd-x64@0.25.12': 139 + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} 140 + engines: {node: '>=18'} 141 + cpu: [x64] 142 + os: [netbsd] 143 + 144 + '@esbuild/openbsd-arm64@0.25.12': 145 + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} 146 + engines: {node: '>=18'} 147 + cpu: [arm64] 148 + os: [openbsd] 149 + 150 + '@esbuild/openbsd-x64@0.25.12': 151 + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} 152 + engines: {node: '>=18'} 153 + cpu: [x64] 154 + os: [openbsd] 155 + 156 + '@esbuild/openharmony-arm64@0.25.12': 157 + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} 158 + engines: {node: '>=18'} 159 + cpu: [arm64] 160 + os: [openharmony] 161 + 162 + '@esbuild/sunos-x64@0.25.12': 163 + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} 164 + engines: {node: '>=18'} 165 + cpu: [x64] 166 + os: [sunos] 167 + 168 + '@esbuild/win32-arm64@0.25.12': 169 + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} 170 + engines: {node: '>=18'} 171 + cpu: [arm64] 172 + os: [win32] 173 + 174 + '@esbuild/win32-ia32@0.25.12': 175 + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} 176 + engines: {node: '>=18'} 177 + cpu: [ia32] 178 + os: [win32] 179 + 180 + '@esbuild/win32-x64@0.25.12': 181 + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} 182 + engines: {node: '>=18'} 183 + cpu: [x64] 184 + os: [win32] 185 + 186 + '@pedrobslisboa/react-client@19.1.0': 187 + resolution: {integrity: sha512-ZvhaqusdprQkpzp8VivH8MSihy8ZlVymo/K9yM8fHYP+LlKLEzb6PR4F+gpRA8mNE4BUZ3CpnzXxPfJjdwBoNA==} 188 + engines: {node: '>=0.10.0'} 189 + peerDependencies: 190 + react: ^19.0.0 191 + 192 + '@rollup/plugin-node-resolve@16.0.3': 193 + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} 194 + engines: {node: '>=14.0.0'} 195 + peerDependencies: 196 + rollup: ^2.78.0||^3.0.0||^4.0.0 197 + peerDependenciesMeta: 198 + rollup: 199 + optional: true 200 + 201 + '@rollup/pluginutils@5.3.0': 202 + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} 203 + engines: {node: '>=14.0.0'} 204 + peerDependencies: 205 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 206 + peerDependenciesMeta: 207 + rollup: 208 + optional: true 209 + 210 + '@rollup/rollup-android-arm-eabi@4.53.2': 211 + resolution: {integrity: sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==} 212 + cpu: [arm] 213 + os: [android] 214 + 215 + '@rollup/rollup-android-arm64@4.53.2': 216 + resolution: {integrity: sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==} 217 + cpu: [arm64] 218 + os: [android] 219 + 220 + '@rollup/rollup-darwin-arm64@4.53.2': 221 + resolution: {integrity: sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==} 222 + cpu: [arm64] 223 + os: [darwin] 224 + 225 + '@rollup/rollup-darwin-x64@4.53.2': 226 + resolution: {integrity: sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==} 227 + cpu: [x64] 228 + os: [darwin] 229 + 230 + '@rollup/rollup-freebsd-arm64@4.53.2': 231 + resolution: {integrity: sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==} 232 + cpu: [arm64] 233 + os: [freebsd] 234 + 235 + '@rollup/rollup-freebsd-x64@4.53.2': 236 + resolution: {integrity: sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==} 237 + cpu: [x64] 238 + os: [freebsd] 239 + 240 + '@rollup/rollup-linux-arm-gnueabihf@4.53.2': 241 + resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} 242 + cpu: [arm] 243 + os: [linux] 244 + 245 + '@rollup/rollup-linux-arm-musleabihf@4.53.2': 246 + resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} 247 + cpu: [arm] 248 + os: [linux] 249 + 250 + '@rollup/rollup-linux-arm64-gnu@4.53.2': 251 + resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} 252 + cpu: [arm64] 253 + os: [linux] 254 + 255 + '@rollup/rollup-linux-arm64-musl@4.53.2': 256 + resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} 257 + cpu: [arm64] 258 + os: [linux] 259 + 260 + '@rollup/rollup-linux-loong64-gnu@4.53.2': 261 + resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} 262 + cpu: [loong64] 263 + os: [linux] 264 + 265 + '@rollup/rollup-linux-ppc64-gnu@4.53.2': 266 + resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} 267 + cpu: [ppc64] 268 + os: [linux] 269 + 270 + '@rollup/rollup-linux-riscv64-gnu@4.53.2': 271 + resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} 272 + cpu: [riscv64] 273 + os: [linux] 274 + 275 + '@rollup/rollup-linux-riscv64-musl@4.53.2': 276 + resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} 277 + cpu: [riscv64] 278 + os: [linux] 279 + 280 + '@rollup/rollup-linux-s390x-gnu@4.53.2': 281 + resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} 282 + cpu: [s390x] 283 + os: [linux] 284 + 285 + '@rollup/rollup-linux-x64-gnu@4.53.2': 286 + resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} 287 + cpu: [x64] 288 + os: [linux] 289 + 290 + '@rollup/rollup-linux-x64-musl@4.53.2': 291 + resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} 292 + cpu: [x64] 293 + os: [linux] 294 + 295 + '@rollup/rollup-openharmony-arm64@4.53.2': 296 + resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==} 297 + cpu: [arm64] 298 + os: [openharmony] 299 + 300 + '@rollup/rollup-win32-arm64-msvc@4.53.2': 301 + resolution: {integrity: sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==} 302 + cpu: [arm64] 303 + os: [win32] 304 + 305 + '@rollup/rollup-win32-ia32-msvc@4.53.2': 306 + resolution: {integrity: sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==} 307 + cpu: [ia32] 308 + os: [win32] 309 + 310 + '@rollup/rollup-win32-x64-gnu@4.53.2': 311 + resolution: {integrity: sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==} 312 + cpu: [x64] 313 + os: [win32] 314 + 315 + '@rollup/rollup-win32-x64-msvc@4.53.2': 316 + resolution: {integrity: sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==} 317 + cpu: [x64] 318 + os: [win32] 319 + 320 + '@types/estree@1.0.8': 321 + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 322 + 323 + '@types/resolve@1.20.2': 324 + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} 325 + 326 + deepmerge@4.3.1: 327 + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 328 + engines: {node: '>=0.10.0'} 329 + 330 + esbuild@0.25.12: 331 + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} 332 + engines: {node: '>=18'} 333 + hasBin: true 334 + 335 + estree-walker@2.0.2: 336 + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 337 + 338 + fdir@6.5.0: 339 + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 340 + engines: {node: '>=12.0.0'} 341 + peerDependencies: 342 + picomatch: ^3 || ^4 343 + peerDependenciesMeta: 344 + picomatch: 345 + optional: true 346 + 347 + fsevents@2.3.3: 348 + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 349 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 350 + os: [darwin] 351 + 352 + function-bind@1.1.2: 353 + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 354 + 355 + hasown@2.0.2: 356 + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 357 + engines: {node: '>= 0.4'} 358 + 359 + is-core-module@2.16.1: 360 + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 361 + engines: {node: '>= 0.4'} 362 + 363 + is-module@1.0.0: 364 + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} 365 + 366 + nanoid@3.3.11: 367 + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 368 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 369 + hasBin: true 370 + 371 + path-parse@1.0.7: 372 + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 373 + 374 + picocolors@1.1.1: 375 + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 376 + 377 + picomatch@4.0.3: 378 + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 379 + engines: {node: '>=12'} 380 + 381 + postcss@8.5.6: 382 + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 383 + engines: {node: ^10 || ^12 || >=14} 384 + 385 + react-dom@19.2.0: 386 + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} 387 + peerDependencies: 388 + react: ^19.2.0 389 + 390 + react@19.2.0: 391 + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} 392 + engines: {node: '>=0.10.0'} 393 + 394 + resolve@1.22.11: 395 + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} 396 + engines: {node: '>= 0.4'} 397 + hasBin: true 398 + 399 + rollup@4.53.2: 400 + resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==} 401 + engines: {node: '>=18.0.0', npm: '>=8.0.0'} 402 + hasBin: true 403 + 404 + scheduler@0.27.0: 405 + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} 406 + 407 + source-map-js@1.2.1: 408 + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 409 + engines: {node: '>=0.10.0'} 410 + 411 + supports-preserve-symlinks-flag@1.0.0: 412 + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 413 + engines: {node: '>= 0.4'} 414 + 415 + tinyglobby@0.2.15: 416 + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 417 + engines: {node: '>=12.0.0'} 418 + 419 + vite@7.2.2: 420 + resolution: {integrity: sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==} 421 + engines: {node: ^20.19.0 || >=22.12.0} 422 + hasBin: true 423 + peerDependencies: 424 + '@types/node': ^20.19.0 || >=22.12.0 425 + jiti: '>=1.21.0' 426 + less: ^4.0.0 427 + lightningcss: ^1.21.0 428 + sass: ^1.70.0 429 + sass-embedded: ^1.70.0 430 + stylus: '>=0.54.8' 431 + sugarss: ^5.0.0 432 + terser: ^5.16.0 433 + tsx: ^4.8.1 434 + yaml: ^2.4.2 435 + peerDependenciesMeta: 436 + '@types/node': 437 + optional: true 438 + jiti: 439 + optional: true 440 + less: 441 + optional: true 442 + lightningcss: 443 + optional: true 444 + sass: 445 + optional: true 446 + sass-embedded: 447 + optional: true 448 + stylus: 449 + optional: true 450 + sugarss: 451 + optional: true 452 + terser: 453 + optional: true 454 + tsx: 455 + optional: true 456 + yaml: 457 + optional: true 458 + 459 + snapshots: 460 + 461 + '@esbuild/aix-ppc64@0.25.12': 462 + optional: true 463 + 464 + '@esbuild/android-arm64@0.25.12': 465 + optional: true 466 + 467 + '@esbuild/android-arm@0.25.12': 468 + optional: true 469 + 470 + '@esbuild/android-x64@0.25.12': 471 + optional: true 472 + 473 + '@esbuild/darwin-arm64@0.25.12': 474 + optional: true 475 + 476 + '@esbuild/darwin-x64@0.25.12': 477 + optional: true 478 + 479 + '@esbuild/freebsd-arm64@0.25.12': 480 + optional: true 481 + 482 + '@esbuild/freebsd-x64@0.25.12': 483 + optional: true 484 + 485 + '@esbuild/linux-arm64@0.25.12': 486 + optional: true 487 + 488 + '@esbuild/linux-arm@0.25.12': 489 + optional: true 490 + 491 + '@esbuild/linux-ia32@0.25.12': 492 + optional: true 493 + 494 + '@esbuild/linux-loong64@0.25.12': 495 + optional: true 496 + 497 + '@esbuild/linux-mips64el@0.25.12': 498 + optional: true 499 + 500 + '@esbuild/linux-ppc64@0.25.12': 501 + optional: true 502 + 503 + '@esbuild/linux-riscv64@0.25.12': 504 + optional: true 505 + 506 + '@esbuild/linux-s390x@0.25.12': 507 + optional: true 508 + 509 + '@esbuild/linux-x64@0.25.12': 510 + optional: true 511 + 512 + '@esbuild/netbsd-arm64@0.25.12': 513 + optional: true 514 + 515 + '@esbuild/netbsd-x64@0.25.12': 516 + optional: true 517 + 518 + '@esbuild/openbsd-arm64@0.25.12': 519 + optional: true 520 + 521 + '@esbuild/openbsd-x64@0.25.12': 522 + optional: true 523 + 524 + '@esbuild/openharmony-arm64@0.25.12': 525 + optional: true 526 + 527 + '@esbuild/sunos-x64@0.25.12': 528 + optional: true 529 + 530 + '@esbuild/win32-arm64@0.25.12': 531 + optional: true 532 + 533 + '@esbuild/win32-ia32@0.25.12': 534 + optional: true 535 + 536 + '@esbuild/win32-x64@0.25.12': 537 + optional: true 538 + 539 + '@pedrobslisboa/react-client@19.1.0(react@19.2.0)': 540 + dependencies: 541 + react: 19.2.0 542 + 543 + '@rollup/plugin-node-resolve@16.0.3(rollup@4.53.2)': 544 + dependencies: 545 + '@rollup/pluginutils': 5.3.0(rollup@4.53.2) 546 + '@types/resolve': 1.20.2 547 + deepmerge: 4.3.1 548 + is-module: 1.0.0 549 + resolve: 1.22.11 550 + optionalDependencies: 551 + rollup: 4.53.2 552 + 553 + '@rollup/pluginutils@5.3.0(rollup@4.53.2)': 554 + dependencies: 555 + '@types/estree': 1.0.8 556 + estree-walker: 2.0.2 557 + picomatch: 4.0.3 558 + optionalDependencies: 559 + rollup: 4.53.2 560 + 561 + '@rollup/rollup-android-arm-eabi@4.53.2': 562 + optional: true 563 + 564 + '@rollup/rollup-android-arm64@4.53.2': 565 + optional: true 566 + 567 + '@rollup/rollup-darwin-arm64@4.53.2': 568 + optional: true 569 + 570 + '@rollup/rollup-darwin-x64@4.53.2': 571 + optional: true 572 + 573 + '@rollup/rollup-freebsd-arm64@4.53.2': 574 + optional: true 575 + 576 + '@rollup/rollup-freebsd-x64@4.53.2': 577 + optional: true 578 + 579 + '@rollup/rollup-linux-arm-gnueabihf@4.53.2': 580 + optional: true 581 + 582 + '@rollup/rollup-linux-arm-musleabihf@4.53.2': 583 + optional: true 584 + 585 + '@rollup/rollup-linux-arm64-gnu@4.53.2': 586 + optional: true 587 + 588 + '@rollup/rollup-linux-arm64-musl@4.53.2': 589 + optional: true 590 + 591 + '@rollup/rollup-linux-loong64-gnu@4.53.2': 592 + optional: true 593 + 594 + '@rollup/rollup-linux-ppc64-gnu@4.53.2': 595 + optional: true 596 + 597 + '@rollup/rollup-linux-riscv64-gnu@4.53.2': 598 + optional: true 599 + 600 + '@rollup/rollup-linux-riscv64-musl@4.53.2': 601 + optional: true 602 + 603 + '@rollup/rollup-linux-s390x-gnu@4.53.2': 604 + optional: true 605 + 606 + '@rollup/rollup-linux-x64-gnu@4.53.2': 607 + optional: true 608 + 609 + '@rollup/rollup-linux-x64-musl@4.53.2': 610 + optional: true 611 + 612 + '@rollup/rollup-openharmony-arm64@4.53.2': 613 + optional: true 614 + 615 + '@rollup/rollup-win32-arm64-msvc@4.53.2': 616 + optional: true 617 + 618 + '@rollup/rollup-win32-ia32-msvc@4.53.2': 619 + optional: true 620 + 621 + '@rollup/rollup-win32-x64-gnu@4.53.2': 622 + optional: true 623 + 624 + '@rollup/rollup-win32-x64-msvc@4.53.2': 625 + optional: true 626 + 627 + '@types/estree@1.0.8': {} 628 + 629 + '@types/resolve@1.20.2': {} 630 + 631 + deepmerge@4.3.1: {} 632 + 633 + esbuild@0.25.12: 634 + optionalDependencies: 635 + '@esbuild/aix-ppc64': 0.25.12 636 + '@esbuild/android-arm': 0.25.12 637 + '@esbuild/android-arm64': 0.25.12 638 + '@esbuild/android-x64': 0.25.12 639 + '@esbuild/darwin-arm64': 0.25.12 640 + '@esbuild/darwin-x64': 0.25.12 641 + '@esbuild/freebsd-arm64': 0.25.12 642 + '@esbuild/freebsd-x64': 0.25.12 643 + '@esbuild/linux-arm': 0.25.12 644 + '@esbuild/linux-arm64': 0.25.12 645 + '@esbuild/linux-ia32': 0.25.12 646 + '@esbuild/linux-loong64': 0.25.12 647 + '@esbuild/linux-mips64el': 0.25.12 648 + '@esbuild/linux-ppc64': 0.25.12 649 + '@esbuild/linux-riscv64': 0.25.12 650 + '@esbuild/linux-s390x': 0.25.12 651 + '@esbuild/linux-x64': 0.25.12 652 + '@esbuild/netbsd-arm64': 0.25.12 653 + '@esbuild/netbsd-x64': 0.25.12 654 + '@esbuild/openbsd-arm64': 0.25.12 655 + '@esbuild/openbsd-x64': 0.25.12 656 + '@esbuild/openharmony-arm64': 0.25.12 657 + '@esbuild/sunos-x64': 0.25.12 658 + '@esbuild/win32-arm64': 0.25.12 659 + '@esbuild/win32-ia32': 0.25.12 660 + '@esbuild/win32-x64': 0.25.12 661 + 662 + estree-walker@2.0.2: {} 663 + 664 + fdir@6.5.0(picomatch@4.0.3): 665 + optionalDependencies: 666 + picomatch: 4.0.3 667 + 668 + fsevents@2.3.3: 669 + optional: true 670 + 671 + function-bind@1.1.2: {} 672 + 673 + hasown@2.0.2: 674 + dependencies: 675 + function-bind: 1.1.2 676 + 677 + is-core-module@2.16.1: 678 + dependencies: 679 + hasown: 2.0.2 680 + 681 + is-module@1.0.0: {} 682 + 683 + nanoid@3.3.11: {} 684 + 685 + path-parse@1.0.7: {} 686 + 687 + picocolors@1.1.1: {} 688 + 689 + picomatch@4.0.3: {} 690 + 691 + postcss@8.5.6: 692 + dependencies: 693 + nanoid: 3.3.11 694 + picocolors: 1.1.1 695 + source-map-js: 1.2.1 696 + 697 + react-dom@19.2.0(react@19.2.0): 698 + dependencies: 699 + react: 19.2.0 700 + scheduler: 0.27.0 701 + 702 + react@19.2.0: {} 703 + 704 + resolve@1.22.11: 705 + dependencies: 706 + is-core-module: 2.16.1 707 + path-parse: 1.0.7 708 + supports-preserve-symlinks-flag: 1.0.0 709 + 710 + rollup@4.53.2: 711 + dependencies: 712 + '@types/estree': 1.0.8 713 + optionalDependencies: 714 + '@rollup/rollup-android-arm-eabi': 4.53.2 715 + '@rollup/rollup-android-arm64': 4.53.2 716 + '@rollup/rollup-darwin-arm64': 4.53.2 717 + '@rollup/rollup-darwin-x64': 4.53.2 718 + '@rollup/rollup-freebsd-arm64': 4.53.2 719 + '@rollup/rollup-freebsd-x64': 4.53.2 720 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.2 721 + '@rollup/rollup-linux-arm-musleabihf': 4.53.2 722 + '@rollup/rollup-linux-arm64-gnu': 4.53.2 723 + '@rollup/rollup-linux-arm64-musl': 4.53.2 724 + '@rollup/rollup-linux-loong64-gnu': 4.53.2 725 + '@rollup/rollup-linux-ppc64-gnu': 4.53.2 726 + '@rollup/rollup-linux-riscv64-gnu': 4.53.2 727 + '@rollup/rollup-linux-riscv64-musl': 4.53.2 728 + '@rollup/rollup-linux-s390x-gnu': 4.53.2 729 + '@rollup/rollup-linux-x64-gnu': 4.53.2 730 + '@rollup/rollup-linux-x64-musl': 4.53.2 731 + '@rollup/rollup-openharmony-arm64': 4.53.2 732 + '@rollup/rollup-win32-arm64-msvc': 4.53.2 733 + '@rollup/rollup-win32-ia32-msvc': 4.53.2 734 + '@rollup/rollup-win32-x64-gnu': 4.53.2 735 + '@rollup/rollup-win32-x64-msvc': 4.53.2 736 + fsevents: 2.3.3 737 + 738 + scheduler@0.27.0: {} 739 + 740 + source-map-js@1.2.1: {} 741 + 742 + supports-preserve-symlinks-flag@1.0.0: {} 743 + 744 + tinyglobby@0.2.15: 745 + dependencies: 746 + fdir: 6.5.0(picomatch@4.0.3) 747 + picomatch: 4.0.3 748 + 749 + vite@7.2.2: 750 + dependencies: 751 + esbuild: 0.25.12 752 + fdir: 6.5.0(picomatch@4.0.3) 753 + picomatch: 4.0.3 754 + postcss: 8.5.6 755 + rollup: 4.53.2 756 + tinyglobby: 0.2.15 757 + optionalDependencies: 758 + fsevents: 2.3.3
-16
public/index.html
··· 1 - <!doctype html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="utf-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 - <link rel="stylesheet" href="/public/index.css" /> 7 - <script type="module" src="/public/index.js" /> 8 - <title>Pegasus</title> 9 - </head> 10 - <body> 11 - <div 12 - id="root" 13 - class="bg-feather-100 font-sans font-normal text-base tracking-normal \ flex items-center justify-center min-h-screen" 14 - ></div> 15 - </body> 16 - </html>
-1
public/index.js
··· 1 - import "../_build/default/pegasus/lib/client/js/src/client/App.js";