From e6ed210d0d7c3b582ca16a50794e5163a38a7207 Mon Sep 17 00:00:00 2001 From: Anirban Kar Date: Mon, 25 Nov 2024 19:53:54 +0530 Subject: [PATCH] work in progress poc git import --- app/components/chat/BaseChat.tsx | 5 + app/components/chat/GitCloneButton.tsx | 24 +++ app/lib/hooks/useGit.ts | 254 +++++++++++++++++++++++++ package.json | 3 + pnpm-lock.yaml | 120 ++++++++++++ 5 files changed, 406 insertions(+) create mode 100644 app/components/chat/GitCloneButton.tsx create mode 100644 app/lib/hooks/useGit.ts diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index b7792bf..c9221c6 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -18,6 +18,8 @@ import Cookies from 'js-cookie'; import styles from './BaseChat.module.scss'; import type { ProviderInfo } from '~/utils/types'; +import GitCloneButton from './GitCloneButton'; +import * as Separator from '@radix-ui/react-separator'; const EXAMPLE_PROMPTS = [ { text: 'Build a todo app in React using Tailwind' }, @@ -208,6 +210,9 @@ export const BaseChat = React.forwardRef( }, )} > + + +
{ + if (!ready) return + let repoUrl=prompt("Enter the Git url") + if (repoUrl) { + await gitClone(repoUrl) + } + } + return ( + { + onClick(e) + + }} className="w-full justify-center" title="Clone A Git Repo"> + Clone A Git Repo +
+ + ) +} diff --git a/app/lib/hooks/useGit.ts b/app/lib/hooks/useGit.ts new file mode 100644 index 0000000..0eb2616 --- /dev/null +++ b/app/lib/hooks/useGit.ts @@ -0,0 +1,254 @@ +import type { WebContainer,FileSystemAPI } from "@webcontainer/api"; +import { useCallback, useEffect, useState } from "react"; +import { webcontainer as webcontainerPromise } from "~/lib/webcontainer"; +import git, { type PromiseFsClient } from 'isomorphic-git' +import http from 'isomorphic-git/http/web' +import Cookies from 'js-cookie'; + + + + +export function useGit() { + const [ready, setReady] = useState(false); + const [webcontainer, setWebcontainer] = useState(); + const [fs, setFs] = useState(); + const lookupSavedPassword=(url:string)=>{ + try { + + // Save updated API keys to cookies with 30 day expiry and secure settings + let creds=Cookies.get(`git:${url}`); + + if (creds) { + const parsedCreds = JSON.parse(creds); + + if (typeof parsedCreds === 'object' && parsedCreds !== null) { + return parsedCreds + } + } + return; + + } catch (error) { + console.error('Error saving API keys to cookies:', error); + return; + } + } + useEffect(()=>{ + webcontainerPromise.then(container=>{ + setWebcontainer(container); + setFs(getFs(container)); + setReady(true); + }) + },[]) + + const gitClone= useCallback(async (url:string)=>{ + if (!webcontainer||!fs||!ready) { + return; + } + let repo = await git.clone({ + fs, + http, + dir: webcontainer.workdir, + url: url, + depth: 1, + singleBranch: true, + corsProxy: 'https://cors.isomorphic-git.org', + onAuth: url => { + let auth = lookupSavedPassword(url) + if (auth) return auth + + if (confirm('This repo is password protected. Ready to enter a username & password?')) { + auth = { + username: prompt('Enter username'), + password: prompt('Enter password'), + } + return auth + } else { + return { cancel: true } + } + } + }) + console.log(repo) + }, [webcontainer]) + return {ready,gitClone} +} + + +interface IFS{ + promises:{ + readFile: PromiseFsClient['promises']['readFile']; + writeFile: PromiseFsClient['promises']['writeFile']; + mkdir:FileSystemAPI['mkdir']; + readdir:FileSystemAPI['readdir']; + rm:FileSystemAPI['rm']; + unlink(path: string): Promise; + stat(path: string): Promise; + lstat(path: string): Promise; + rmdir(path: string): Promise; + readlink?(path: string): Promise; + symlink?(target: string, path: string): Promise; + chmod?(path: string, mode: number): Promise; + } +} +const getFs: (c: WebContainer) => PromiseFsClient = (webcontainer: WebContainer)=> ({ + promises:{ + readFile: async (path: string, options: any) => { + let encoding = options.encoding; + let relativePath = pathUtils.relative(webcontainer.workdir,path); + console.log('readFile', relativePath, encoding); + return await webcontainer.fs.readFile(relativePath,encoding); + }, + writeFile: async (path: string, data: any, options: any) => { + let encoding = options.encoding; + let relativePath = pathUtils.relative(webcontainer.workdir,path); + console.log('writeFile', {relativePath,data,encoding}); + return await webcontainer.fs.writeFile(relativePath, data, { ...options,encoding}); + }, + mkdir: async (path: string, options: any) => { + let relativePath = pathUtils.relative(webcontainer.workdir, path); + console.log('mkdir', relativePath,options); + return await webcontainer.fs.mkdir(relativePath,{...options,recursive:true}) + }, + readdir: async (path: string,options:any) => { + let relativePath = pathUtils.relative(webcontainer.workdir, path); + console.log('readdir', relativePath,options); + return await webcontainer.fs.readdir(relativePath,options) + }, + rm: async (path: string,options:any) => { + + let relativePath = pathUtils.relative(webcontainer.workdir, path); + console.log('rm', relativePath,options); + + return await webcontainer.fs.rm(relativePath, { ...options||{} }) + }, + rmdir: async (path: string,options:any) => { + let relativePath = pathUtils.relative(webcontainer.workdir, path); + console.log('rmdir', relativePath, options); + return await webcontainer.fs.rm(relativePath, { recursive: true,...options}) + }, + + // Mock implementations for missing functions + unlink: async (path: string) => { + // unlink is just removing a single file + let relativePath = pathUtils.relative(webcontainer.workdir, path); + return await webcontainer.fs.rm(relativePath, { recursive: false }); + }, + + stat: async (path: string) => { + try { + let relativePath = pathUtils.relative(webcontainer.workdir, path); + let resp = await webcontainer.fs.readdir(pathUtils.dirname(relativePath),{withFileTypes:true}) + let name = pathUtils.basename(relativePath) + let fileInfo=resp.find(x=>x.name==name) + if(!fileInfo){ + throw new Error(`ENOENT: no such file or directory, stat '${path}'`); + } + return { + isFile: () => fileInfo.isFile(), + isDirectory: () => fileInfo.isDirectory(), + isSymbolicLink: () => false, + size: 1, + mode: 0o666, // Default permissions + mtimeMs: Date.now(), + uid: 1000, + gid: 1000 + }; + } catch (error) { + const err = new Error(`ENOENT: no such file or directory, stat '${path}'`) as NodeJS.ErrnoException; + err.code = 'ENOENT'; + err.errno = -2; + err.syscall = 'stat'; + err.path = path; + throw err; + } + }, + + lstat: async (path: string) => { + // For basic usage, lstat can return the same as stat + // since we're not handling symbolic links + return await getFs(webcontainer).promises.stat(path); + }, + + readlink: async (path: string) => { + // Since WebContainer doesn't support symlinks, + // we'll throw a "not a symbolic link" error + throw new Error(`EINVAL: invalid argument, readlink '${path}'`); + }, + + symlink: async (target: string, path: string) => { + // Since WebContainer doesn't support symlinks, + // we'll throw a "operation not supported" error + throw new Error(`EPERM: operation not permitted, symlink '${target}' -> '${path}'`); + }, + + chmod: async (path: string, mode: number) => { + // WebContainer doesn't support changing permissions, + // but we can pretend it succeeded for compatibility + return await Promise.resolve(); + } + } + }) + +const pathUtils = { + dirname: (path: string) => { + // Handle empty or just filename cases + if (!path || !path.includes('/')) return '.'; + + // Remove trailing slashes + path = path.replace(/\/+$/, ''); + + // Get directory part + return path.split('/').slice(0, -1).join('/') || '/'; + }, + + basename: (path: string, ext?: string) => { + // Remove trailing slashes + path = path.replace(/\/+$/, ''); + + // Get the last part of the path + const base = path.split('/').pop() || ''; + + // If extension is provided, remove it from the result + if (ext && base.endsWith(ext)) { + return base.slice(0, -ext.length); + } + + return base; + }, + relative: (from: string, to: string): string => { + // Handle empty inputs + if (!from || !to) return '.'; + + // Normalize paths by removing trailing slashes and splitting + const normalizePathParts = (p: string) => + p.replace(/\/+$/, '') + .split('/') + .filter(Boolean); + + const fromParts = normalizePathParts(from); + const toParts = normalizePathParts(to); + + // Find common parts at the start of both paths + let commonLength = 0; + const minLength = Math.min(fromParts.length, toParts.length); + + for (let i = 0; i < minLength; i++) { + if (fromParts[i] !== toParts[i]) break; + commonLength++; + } + + // Calculate the number of "../" needed + const upCount = fromParts.length - commonLength; + + // Get the remaining path parts we need to append + const remainingPath = toParts.slice(commonLength); + + // Construct the relative path + const relativeParts = [ + ...Array(upCount).fill('..'), + ...remainingPath + ]; + + // Handle empty result case + return relativeParts.length === 0 ? '.' : relativeParts.join('/'); + } +} \ No newline at end of file diff --git a/package.json b/package.json index 16c59f7..1d33db7 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@openrouter/ai-sdk-provider": "^0.0.5", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.4", "@remix-run/cloudflare": "^2.10.2", "@remix-run/cloudflare-pages": "^2.10.2", @@ -71,6 +72,7 @@ "file-saver": "^2.0.5", "framer-motion": "^11.2.12", "isbot": "^4.1.0", + "isomorphic-git": "^1.27.1", "istextorbinary": "^9.5.0", "jose": "^5.6.3", "js-cookie": "^3.0.5", @@ -103,6 +105,7 @@ "fast-glob": "^3.3.2", "is-ci": "^3.0.1", "node-fetch": "^3.3.2", + "pnpm": "9.4.0", "prettier": "^3.3.2", "sass-embedded": "^1.80.3", "typescript": "^5.5.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 951d1a4..67773c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -98,6 +98,9 @@ importers: '@radix-ui/react-dropdown-menu': specifier: ^2.1.1 version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-separator': + specifier: ^1.1.0 + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-tooltip': specifier: ^1.1.4 version: 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -146,6 +149,9 @@ importers: isbot: specifier: ^4.1.0 version: 4.4.0 + isomorphic-git: + specifier: ^1.27.1 + version: 1.27.1 istextorbinary: specifier: ^9.5.0 version: 9.5.0 @@ -237,6 +243,9 @@ importers: node-fetch: specifier: ^3.3.2 version: 3.3.2 + pnpm: + specifier: 9.4.0 + version: 9.4.0 prettier: specifier: ^3.3.2 version: 3.3.2 @@ -1607,6 +1616,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-separator@1.1.0': + resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.1.0': resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: @@ -2371,6 +2393,9 @@ packages: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true + async-lock@1.4.1: + resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -2564,6 +2589,9 @@ packages: cipher-base@1.0.4: resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + clean-git-ref@2.0.1: + resolution: {integrity: sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==} + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -2673,6 +2701,11 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + create-ecdh@4.0.4: resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} @@ -2745,6 +2778,10 @@ packages: decode-named-character-reference@1.0.2: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dedent@1.5.3: resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} peerDependencies: @@ -2812,6 +2849,9 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff3@0.0.3: + resolution: {integrity: sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==} + diff@5.2.0: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} @@ -3545,6 +3585,11 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isomorphic-git@1.27.1: + resolution: {integrity: sha512-X32ph5zIWfT75QAqW2l3JCIqnx9/GWd17bRRehmn3qmWc34OYbSXY6Cxv0o9bIIY+CWugoN4nQFHNA+2uYf2nA==} + engines: {node: '>=12'} + hasBin: true + isomorphic-timers-promises@1.0.1: resolution: {integrity: sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==} engines: {node: '>=10'} @@ -4035,6 +4080,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + miniflare@3.20240701.0: resolution: {integrity: sha512-m9+I+7JNyqDGftCMKp9cK9pCZkK72hAL2mM9IWwhct+ZmucLBA8Uu6+rHQqA5iod86cpwOkrB2PrPA3wx9YNgw==} engines: {node: '>=16.13'} @@ -4056,6 +4105,9 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minimisted@2.0.1: + resolution: {integrity: sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==} + minipass-collect@1.0.2: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} engines: {node: '>= 8'} @@ -4380,6 +4432,10 @@ packages: engines: {node: '>=0.10'} hasBin: true + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + pkg-dir@5.0.0: resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} engines: {node: '>=10'} @@ -4387,6 +4443,11 @@ packages: pkg-types@1.1.1: resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==} + pnpm@9.4.0: + resolution: {integrity: sha512-9Um4pSydK4U2di+ZwHIiBe/Fr5E+d4NdvMw7CwssqefcgCK3gGLBcpHEjoh0nHDOiOtadPH6jEv14Yu0bIvYOg==} + engines: {node: '>=18.12'} + hasBin: true + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -5006,6 +5067,12 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + sirv@2.0.4: resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} engines: {node: '>= 10'} @@ -7043,6 +7110,15 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-slot@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -8004,6 +8080,8 @@ snapshots: astring@1.8.6: {} + async-lock@1.4.1: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -8260,6 +8338,8 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 + clean-git-ref@2.0.1: {} + clean-stack@2.2.0: {} cli-cursor@3.1.0: @@ -8351,6 +8431,8 @@ snapshots: core-util-is@1.0.3: {} + crc-32@1.2.2: {} + create-ecdh@4.0.4: dependencies: bn.js: 4.12.0 @@ -8428,6 +8510,10 @@ snapshots: dependencies: character-entities: 2.0.2 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + dedent@1.5.3: {} deep-eql@5.0.2: {} @@ -8479,6 +8565,8 @@ snapshots: diff-sequences@29.6.3: {} + diff3@0.0.3: {} + diff@5.2.0: {} diffie-hellman@5.0.3: @@ -9398,6 +9486,20 @@ snapshots: isexe@2.0.0: {} + isomorphic-git@1.27.1: + dependencies: + async-lock: 1.4.1 + clean-git-ref: 2.0.1 + crc-32: 1.2.2 + diff3: 0.0.3 + ignore: 5.3.1 + minimisted: 2.0.1 + pako: 1.0.11 + pify: 4.0.1 + readable-stream: 3.6.2 + sha.js: 2.4.11 + simple-get: 4.0.1 + isomorphic-timers-promises@1.0.1: {} istextorbinary@9.5.0: @@ -10265,6 +10367,8 @@ snapshots: mimic-fn@4.0.0: {} + mimic-response@3.1.0: {} + miniflare@3.20240701.0: dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -10298,6 +10402,10 @@ snapshots: minimist@1.2.8: {} + minimisted@2.0.1: + dependencies: + minimist: 1.2.8 + minipass-collect@1.0.2: dependencies: minipass: 3.3.6 @@ -10639,6 +10747,8 @@ snapshots: pidtree@0.6.0: {} + pify@4.0.1: {} + pkg-dir@5.0.0: dependencies: find-up: 5.0.0 @@ -10649,6 +10759,8 @@ snapshots: mlly: 1.7.1 pathe: 1.1.2 + pnpm@9.4.0: {} + possible-typed-array-names@1.0.0: {} postcss-discard-duplicates@5.1.0(postcss@8.4.38): @@ -11314,6 +11426,14 @@ snapshots: signal-exit@4.1.0: {} + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + sirv@2.0.4: dependencies: '@polka/url': 1.0.0-next.25