Compare commits

...

38 Commits

Author SHA1 Message Date
Mauricio Siu
385fbf4af5 Merge pull request #355 from Dokploy/canary
v0.6.3
2024-08-16 22:26:35 -06:00
Mauricio Siu
44e75ee7e1 refactor: update deps 2024-08-16 22:10:23 -06:00
Mauricio Siu
6b4d6eac1d chore: bump version 2024-08-16 22:07:02 -06:00
Mauricio Siu
175e84f50e refactor: update container id 2024-08-13 23:29:51 -06:00
Mauricio Siu
efb646c43d Merge pull request #346 from Dokploy/282-add-option-to-revert-dokploy-version-opt-in-based-auto-updates
282 add option to revert dokploy version opt in based auto updates
2024-08-13 23:12:57 -06:00
Mauricio Siu
fa950dae39 fix(settings): prevent to download the latest image on reload 2024-08-13 23:04:21 -06:00
Mauricio Siu
712ad25e7a feat(permission): add permission to access to ssh key section 2024-08-13 22:19:04 -06:00
Mauricio Siu
35a41e774e Merge pull request #343 from Tuluobo/bugfix/delete_service_with_container
fix(ui): close dialog after templete selected & add config editor line wrapping
2024-08-13 22:02:33 -06:00
Mauricio Siu
c2ac193fbe Merge pull request #344 from Dokploy/340-dokploy-postgres-and-redis-are-exposed
fix(services): set published port 0 to prevent swarm assign random po…
2024-08-13 21:56:12 -06:00
Mauricio Siu
ce3c89a715 Merge pull request #342 from Dokploy/326-dokploy-doesnt-persist-registry-tokens
fix(docker): add root docker to prevent registry delete in each resta…
2024-08-13 21:52:07 -06:00
Mauricio Siu
96f7206a1d fix(services): set published port 0 to prevent swarm assign random ports #340 2024-08-13 21:49:21 -06:00
Mauricio Siu
b7ace886f3 fix(docker): add root docker to prevent registry delete in each restart/update dokploy server #326 2024-08-13 20:40:34 -06:00
Mauricio Siu
5dc330eaa3 Merge pull request #341 from Dokploy/337-incorrect-github-apps-install-link-when-app-name-contain-special-characters
fix(github): use github url to install the application #337
2024-08-13 20:04:46 -06:00
Mauricio Siu
b7f5bee2f8 fix(github): use github url to install the application #337 2024-08-13 19:57:10 -06:00
Tuluobo
19ee5f073b feat: add line wrapping for traefik config editor 2024-08-13 20:51:50 +08:00
Tuluobo
1fd4a6ae80 refactor: close dialog after selected template 2024-08-13 19:38:09 +08:00
Mauricio Siu
3c8a412014 Merge pull request #339 from Vladislav-CS/patch-1
fix: responsive design in the project settings page
2024-08-10 16:00:06 -06:00
Vladislav Popovič
eee617719b Update show-deployments.tsx 2024-08-10 22:19:15 +03:00
Mauricio Siu
fc611946a6 Merge pull request #334 from Vladislav-CS/fix-typos
fix: typos
2024-08-08 10:59:22 -06:00
Vladislav Popovič
af13c84968 Update add-template.tsx 2024-08-08 18:21:35 +03:00
Vladislav Popovič
ddb78ef8dd Update show-ssh-keys.tsx 2024-08-08 18:17:12 +03:00
Mauricio Siu
3590f3bed2 Merge pull request #332 from Dokploy/canary
v0.6.2
2024-08-07 21:48:49 -06:00
Mauricio Siu
c70089ee53 refactor(logs): add error log in build application 2024-08-07 21:41:25 -06:00
Mauricio Siu
161e479a0b chore(version): bump version 2024-08-07 21:08:42 -06:00
Mauricio Siu
bd735bfb64 Merge pull request #331 from Dokploy/322-git-submodules-are-not-cloned
fix(git): add --recursive-submodules flag
2024-08-07 21:09:29 -06:00
Mauricio Siu
85c814620e Merge pull request #330 from Dokploy/fix/add-validation-git-source
fix(git): don't add to ssh known host when is a http or https url
2024-08-07 20:59:42 -06:00
Mauricio Siu
fb013fe4ec fix(git): add --recursive-submodules flag 2024-08-07 20:58:16 -06:00
Mauricio Siu
90a1bd9027 fix(git): don't add to ssh known host when is a http or https url 2024-08-07 20:51:27 -06:00
Mauricio Siu
610ef8f35c Update README.md 2024-08-05 10:23:46 -06:00
Mauricio Siu
9b2fcaea31 Merge pull request #317 from Dokploy/canary
v0.6.1
2024-08-03 15:46:05 -06:00
Mauricio Siu
2ffa95b9fa chore(version): bump version 2024-08-03 15:34:09 -06:00
Mauricio Siu
559872c4e4 Merge pull request #316 from Dokploy/315-docs-website-error-dialogclose-must-be-used-within-dialog
fix(docs): update dependencies
2024-08-03 15:32:36 -06:00
Mauricio Siu
85642ed5f2 refactor(docs): add volumes deployments 2024-08-03 15:14:02 -06:00
Mauricio Siu
8bf701d2f2 fix(docs): update dependencies 2024-08-03 15:06:47 -06:00
Mauricio Siu
38809a2034 Merge pull request #314 from Dokploy/fix/add-file-path
fix(template): add missing file path
2024-08-03 15:05:31 -06:00
Mauricio Siu
4bd6ec2232 fix(templates): use filePath instead of mountPath 2024-08-03 14:59:20 -06:00
Mauricio Siu
95899b7208 fix(templates): update path file path 2024-08-02 13:45:20 -06:00
Mauricio Siu
ac26bb95e3 fix(template): add missing file path 2024-08-02 13:40:25 -06:00
40 changed files with 3320 additions and 172 deletions

View File

@@ -1,7 +1,7 @@
<div align="center">
<h1 align="center">Dokploy</h1>
<div>
<img style="object-fit: cover; border-radius:20px;" align="center" width="50%"src="https://raw.githubusercontent.com/Dokploy/docs/main/public/logo.png" >
<img style="object-fit: cover; border-radius:20px;" align="center" width="50%"src="https://dokploy.com/og.png" >
</div>

View File

@@ -3,13 +3,14 @@ title: "Overview"
description: "Learn how to use Docker Compose with Dokploy"
---
import { Callout } from "fumadocs-ui/components/callout";
Dokploy integrates with Docker Compose and Docker Stack to provide flexible deployment solutions. Whether you are developing locally or deploying at scale, Dokploy facilitates application management through these powerful Docker tools.
### Configuration Methods
Dokploy provides two methods for creating Docker Compose configurations:
- **Docker Compose**: Ideal for standard Docker Compose configurations.
- **Stack**: Geared towards orchestrating applications using Docker Swarm. Note that some Docker Compose features, such as `build`, are not available in this mode.
@@ -21,7 +22,7 @@ Configure the source of your code, the way your application is built, and also m
A code editor within Dokploy allows you to specify environment variables for your Docker Compose file. By default, Dokploy creates a `.env` file in the specified Docker Compose file path.
### Monitoring
### Monitoring
Monitor each service individually within Dokploy. If your application consists of multiple services, each can be monitored separately to ensure optimal performance.
@@ -29,7 +30,6 @@ Monitor each service individually within Dokploy. If your application consists o
Access detailed logs for each service through the Dokploy log viewer, which can help in troubleshooting and ensuring the stability of your services.
### Deployments
You can view the last 10 deployments of your application. When you deploy your application in real time, a new deployment record will be created and it will gradually show you how your application is being built.
@@ -38,7 +38,6 @@ We also offer a button to cancel deployments that are in queue. Note that those
We provide a webhook so that you can trigger your own deployments by pushing to your GitHub, Gitea, GitLab, Bitbucket repository.
### Advanced
This section provides advanced configuration options for experienced users. It includes tools for custom commands within the container and volumes.
@@ -46,4 +45,32 @@ This section provides advanced configuration options for experienced users. It i
- **Command**: Dokploy has a defined command to run the Docker Compose file, ensuring complete control through the UI. However, you can append flags or options to the command.
- **Volumes**: To ensure data persistence across deployments, configure storage volumes for your application.
<ImageZoom src="/assets/images/compose/overview.png" width={800} height={630} quality={100} priority alt='home og image' className="rounded-lg" />
<ImageZoom
src="/assets/images/compose/overview.png"
width={800}
height={630}
quality={100}
priority
alt="home og image"
className="rounded-lg"
/>
<Callout title="Volumes">
Docker volumes are a way to persist data generated and used by Docker containers. They are particularly useful for maintaining data between container restarts or for sharing data among different containers.
To bind a volume to the host machine, you can use the following syntax in your docker-compose.yml file, but this way will clean up the volumes when a new deployment is made:
```yaml
volumes:
- "/folder:/path/in/container" ❌
```
It's recommended to use the ../files folder to ensure your data persists between deployments. For example:
```yaml
volumes:
- "../files/my-database:/var/lib/mysql" ✅
- "../files/my-configs:/etc/my-app/config" ✅
```
</Callout>

View File

@@ -10,10 +10,10 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"fumadocs-core": "12.2.2",
"fumadocs-mdx": "8.2.33",
"fumadocs-openapi": "^3.1.3",
"fumadocs-ui": "12.2.2",
"fumadocs-core": "^12.5.6",
"fumadocs-mdx": "^8.2.34",
"fumadocs-openapi": "^3.3.0",
"fumadocs-ui": "^12.5.6",
"lucide-react": "^0.394.0",
"next": "^14.2.4",
"react": "^18.3.1",

View File

@@ -46,6 +46,7 @@ export const ShowTraefikConfig = ({ applicationId }: Props) => {
<div className="flex flex-col pt-2 relative">
<div className="flex flex-col gap-6 max-h-[35rem] min-h-[10rem] overflow-y-auto">
<CodeEditor
lineWrapping
value={data || "Empty"}
disabled
className="font-mono"

View File

@@ -144,6 +144,7 @@ export const UpdateTraefikConfig = ({ applicationId }: Props) => {
<FormLabel>Traefik config</FormLabel>
<FormControl>
<CodeEditor
lineWrapping
wrapperClassName="h-[35rem] font-mono"
placeholder={`http:
routers:

View File

@@ -53,7 +53,7 @@ export const ShowDeployments = ({ applicationId }: Props) => {
<div className="flex flex-row items-center gap-2 flex-wrap">
<span>Webhook URL: </span>
<div className="flex flex-row items-center gap-2">
<span className="text-muted-foreground">
<span className="break-all text-muted-foreground">
{`${url}/api/deploy/${data?.refreshToken}`}
</span>
<RefreshToken applicationId={applicationId} />
@@ -72,7 +72,7 @@ export const ShowDeployments = ({ applicationId }: Props) => {
{deployments?.map((deployment) => (
<div
key={deployment.deploymentId}
className="flex items-center justify-between rounded-lg border p-4"
className="flex items-center justify-between rounded-lg border p-4 gap-2"
>
<div className="flex flex-col">
<span className="flex items-center gap-4 font-medium capitalize text-foreground">
@@ -87,7 +87,7 @@ export const ShowDeployments = ({ applicationId }: Props) => {
{deployment.title}
</span>
{deployment.description && (
<span className="text-sm text-muted-foreground">
<span className="break-all text-sm text-muted-foreground">
{deployment.description}
</span>
)}

View File

@@ -104,6 +104,7 @@ export const ShowTraefikFile = ({ path }: Props) => {
</FormDescription>
<FormControl>
<CodeEditor
lineWrapping
wrapperClassName="h-[35rem] font-mono"
placeholder={`http:
routers:

View File

@@ -55,6 +55,7 @@ interface Props {
export const AddTemplate = ({ projectId }: Props) => {
const [query, setQuery] = useState("");
const [open, setOpen] = useState(false);
const { data } = api.compose.templates.useQuery();
const [selectedTags, setSelectedTags] = useState<string[]>([]);
const { data: tags, isLoading: isLoadingTags } =
@@ -75,14 +76,14 @@ export const AddTemplate = ({ projectId }: Props) => {
}) || [];
return (
<Dialog>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger className="w-full">
<DropdownMenuItem
className="w-full cursor-pointer space-x-3"
onSelect={(e) => e.preventDefault()}
>
<PuzzleIcon className="size-4 text-muted-foreground" />
<span>Templates</span>
<span>Template</span>
</DropdownMenuItem>
</DialogTrigger>
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-7xl p-0">
@@ -283,6 +284,7 @@ export const AddTemplate = ({ projectId }: Props) => {
utils.project.one.invalidate({
projectId,
});
setOpen(false);
})
.catch(() => {
toast.error(

View File

@@ -9,36 +9,11 @@ import {
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { api } from "@/utils/api";
import { format } from "date-fns";
import { BadgeCheck } from "lucide-react";
import Link from "next/link";
import React, { useEffect, useState } from "react";
import { RemoveGithubApp } from "./remove-github-app";
export const generateName = () => {
const n1 = ["Blue", "Green", "Red", "Orange", "Violet", "Indigo", "Yellow"];
const n2 = [
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
"Seven",
"Eight",
"Nine",
"Zero",
];
return `Dokploy-${n1[Math.round(Math.random() * (n1.length - 1))]}-${
n2[Math.round(Math.random() * (n2.length - 1))]
}`;
};
function slugify(text: string) {
return text
.toLowerCase()
.replace(/[\s\^&*()+=!]+/g, "-")
.replace(/[\$.,*+~()'"!:@^&]+/g, "")
.replace(/-+/g, "-")
.replace(/^-+|-+$/g, "");
}
export const GithubSetup = () => {
const [isOrganization, setIsOrganization] = useState(false);
@@ -52,10 +27,9 @@ export const GithubSetup = () => {
const manifest = JSON.stringify(
{
redirect_url: `${origin}/api/redirect?authId=${data?.authId}`,
name: generateName(),
name: `Dokploy-${format(new Date(), "yyyy-MM-dd")}`,
url: origin,
hook_attributes: {
// JUST FOR TESTING
url: `${url}/api/deploy/github`,
// url: `${origin}/api/webhook`, // Aquí especificas la URL del endpoint de tu webhook
},
@@ -95,8 +69,8 @@ export const GithubSetup = () => {
</div>
<div className="flex items-end gap-4 flex-wrap">
<RemoveGithubApp />
{/* <Link
href={`https://github.com/settings/apps/${data?.githubAppName}`}
<Link
href={`${data?.githubAppName}`}
target="_blank"
className={buttonVariants({
className: "w-fit",
@@ -104,7 +78,7 @@ export const GithubSetup = () => {
})}
>
<span className="text-sm">Manage Github App</span>
</Link> */}
</Link>
</div>
</div>
) : (
@@ -119,9 +93,9 @@ export const GithubSetup = () => {
<div className="flex flex-row gap-4">
<Link
href={`https://github.com/apps/${slugify(
data.githubAppName,
)}/installations/new?state=gh_setup:${data?.authId}`}
href={`${
data.githubAppName
}/installations/new?state=gh_setup:${data?.authId}`}
className={buttonVariants({ className: "w-fit" })}
>
Install Github App

View File

@@ -22,7 +22,7 @@ export const ShowDestinations = () => {
<CardHeader>
<CardTitle className="text-xl">SSH Keys</CardTitle>
<CardDescription>
Use SSH to beeing able cloning from private repositories.
Use SSH to be able to clone from private repositories.
</CardDescription>
</CardHeader>
<CardContent className="space-y-2 pt-4">

View File

@@ -39,6 +39,7 @@ const addPermissions = z.object({
canAccessToTraefikFiles: z.boolean().optional().default(false),
canAccessToDocker: z.boolean().optional().default(false),
canAccessToAPI: z.boolean().optional().default(false),
canAccessToSSHKeys: z.boolean().optional().default(false),
});
type AddPermissions = z.infer<typeof addPermissions>;
@@ -82,6 +83,7 @@ export const AddUserPermissions = ({ userId }: Props) => {
canAccessToTraefikFiles: data.canAccessToTraefikFiles,
canAccessToDocker: data.canAccessToDocker,
canAccessToAPI: data.canAccessToAPI,
canAccessToSSHKeys: data.canAccessToSSHKeys,
});
}
}, [form, form.formState.isSubmitSuccessful, form.reset, data]);
@@ -98,6 +100,7 @@ export const AddUserPermissions = ({ userId }: Props) => {
accesedServices: data.accesedServices || [],
canAccessToDocker: data.canAccessToDocker,
canAccessToAPI: data.canAccessToAPI,
canAccessToSSHKeys: data.canAccessToSSHKeys,
})
.then(async () => {
toast.success("Permissions updated");
@@ -270,6 +273,26 @@ export const AddUserPermissions = ({ userId }: Props) => {
</FormItem>
)}
/>
<FormField
control={form.control}
name="canAccessToSSHKeys"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
<div className="space-y-0.5">
<FormLabel>Access to SSH Keys</FormLabel>
<FormDescription>
Allow to users to access to the SSH Keys section
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="accesedProjects"

View File

@@ -106,6 +106,7 @@ export const ShowMainTraefikConfig = ({ children }: Props) => {
<FormLabel>Traefik config</FormLabel>
<FormControl>
<CodeEditor
lineWrapping
wrapperClassName="h-[35rem] font-mono"
placeholder={`providers:
docker:

View File

@@ -109,6 +109,7 @@ export const ShowServerTraefikConfig = ({ children }: Props) => {
<FormLabel>Traefik config</FormLabel>
<FormControl>
<CodeEditor
lineWrapping
wrapperClassName="h-[35rem] font-mono"
placeholder={`http:
routers:

View File

@@ -79,6 +79,16 @@ export const SettingsLayout = ({ children }: Props) => {
},
]
: []),
...(user?.canAccessToSSHKeys
? [
{
title: "SSH Keys",
label: "",
icon: KeyRound,
href: "/dashboard/settings/ssh-keys",
},
]
: []),
]}
/>
</div>

View File

@@ -3,6 +3,7 @@ import { json } from "@codemirror/lang-json";
import { yaml } from "@codemirror/lang-yaml";
import { StreamLanguage } from "@codemirror/language";
import { properties } from "@codemirror/legacy-modes/mode/properties";
import { EditorView } from "@codemirror/view";
import { githubDark, githubLight } from "@uiw/codemirror-theme-github";
import CodeMirror, { type ReactCodeMirrorProps } from "@uiw/react-codemirror";
import { useTheme } from "next-themes";
@@ -10,6 +11,7 @@ interface Props extends ReactCodeMirrorProps {
wrapperClassName?: string;
disabled?: boolean;
language?: "yaml" | "json" | "properties";
lineWrapping?: boolean;
}
export const CodeEditor = ({
@@ -36,6 +38,7 @@ export const CodeEditor = ({
: language === "json"
? json()
: StreamLanguage.define(properties),
props.lineWrapping ? EditorView.lineWrapping : [],
]}
{...props}
editable={!props.disabled}

View File

@@ -0,0 +1 @@
ALTER TABLE "user" ADD COLUMN "canAccessToSSHKeys" boolean DEFAULT false NOT NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -211,6 +211,13 @@
"when": 1722578386823,
"tag": "0029_colossal_zodiak",
"breakpoints": true
},
{
"idx": 30,
"version": "6",
"when": 1723608499147,
"tag": "0030_little_kabuki",
"breakpoints": true
}
]
}

View File

@@ -1,6 +1,6 @@
{
"name": "dokploy",
"version": "v0.6.0",
"version": "v0.6.3",
"private": true,
"license": "Apache-2.0",
"type": "module",
@@ -39,6 +39,7 @@
"@codemirror/lang-yaml": "^6.1.1",
"@codemirror/language": "^6.10.1",
"@codemirror/legacy-modes": "6.4.0",
"@codemirror/view": "6.29.0",
"@dokploy/trpc-openapi": "0.0.4",
"@faker-js/faker": "^8.4.1",
"@hookform/resolvers": "^3.3.4",

View File

@@ -35,7 +35,7 @@ export default async function handler(
.update(admins)
.set({
githubAppId: data.id,
githubAppName: data.name,
githubAppName: data.html_url,
githubClientId: data.client_id,
githubClientSecret: data.client_secret,
githubWebhookSecret: data.webhook_secret,

View File

@@ -1,9 +1,12 @@
import { ShowDestinations } from "@/components/dashboard/settings/ssh-keys/show-ssh-keys";
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { SettingsLayout } from "@/components/layouts/settings-layout";
import { appRouter } from "@/server/api/root";
import { validateRequest } from "@/server/auth/auth";
import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext } from "next";
import React, { type ReactElement } from "react";
import superjson from "superjson";
const Page = () => {
return (
@@ -26,7 +29,7 @@ export async function getServerSideProps(
ctx: GetServerSidePropsContext<{ serviceId: string }>,
) {
const { user, session } = await validateRequest(ctx.req, ctx.res);
if (!user || user.rol === "user") {
if (!user) {
return {
redirect: {
permanent: true,
@@ -34,8 +37,45 @@ export async function getServerSideProps(
},
};
}
const { req, res, resolvedUrl } = ctx;
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {
req: req as any,
res: res as any,
db: null as any,
session: session,
user: user,
},
transformer: superjson,
});
return {
props: {},
};
try {
await helpers.project.all.prefetch();
const auth = await helpers.auth.get.fetch();
if (auth.rol === "user") {
const user = await helpers.user.byAuthId.fetch({
authId: auth.id,
});
if (!user.canAccessToSSHKeys) {
return {
redirect: {
permanent: true,
destination: "/",
},
};
}
}
return {
props: {
trpcState: helpers.dehydrate(),
},
};
} catch (error) {
return {
props: {},
};
}
}

View File

@@ -227,7 +227,8 @@ export const composeRouter = createTRPCRouter({
if (mounts && mounts?.length > 0) {
for (const mount of mounts) {
await createMount({
mountPath: mount.mountPath,
filePath: mount.filePath,
mountPath: "",
content: mount.content,
serviceId: compose.composeId,
serviceType: "compose",

View File

@@ -20,6 +20,7 @@ import {
} from "@/server/utils/docker/utils";
import { recreateDirectory } from "@/server/utils/filesystem/directory";
import { sendDockerCleanupNotifications } from "@/server/utils/notifications/docker-cleanup";
import { execAsync } from "@/server/utils/process/execAsync";
import { spawnAsync } from "@/server/utils/process/spawnAsync";
import {
readConfig,
@@ -49,14 +50,10 @@ import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
export const settingsRouter = createTRPCRouter({
reloadServer: adminProcedure.mutation(async () => {
await spawnAsync("docker", [
"service",
"update",
"--force",
"--image",
getDokployImage(),
"dokploy",
]);
const { stdout } = await execAsync(
"docker service inspect dokploy --format '{{.ID}}'",
);
await execAsync(`docker service update --force ${stdout.trim()}`);
return true;
}),
reloadTraefik: adminProcedure.mutation(async () => {

View File

@@ -34,21 +34,23 @@ export const sshRouter = createTRPCRouter({
});
}
}),
remove: adminProcedure.input(apiRemoveSshKey).mutation(async ({ input }) => {
try {
return await removeSSHKeyById(input.sshKeyId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error to delete this ssh key",
});
}
}),
remove: protectedProcedure
.input(apiRemoveSshKey)
.mutation(async ({ input }) => {
try {
return await removeSSHKeyById(input.sshKeyId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error to delete this ssh key",
});
}
}),
one: protectedProcedure.input(apiFindOneSshKey).query(async ({ input }) => {
const sshKey = await findSSHKeyById(input.sshKeyId);
return sshKey;
}),
all: adminProcedure.query(async () => {
all: protectedProcedure.query(async () => {
return await db.query.sshKeys.findMany({});
}),
generate: protectedProcedure
@@ -56,15 +58,17 @@ export const sshRouter = createTRPCRouter({
.mutation(async ({ input }) => {
return await generateSSHKey(input.type);
}),
update: adminProcedure.input(apiUpdateSshKey).mutation(async ({ input }) => {
try {
return await updateSSHKeyById(input);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error to update this ssh key",
cause: error,
});
}
}),
update: protectedProcedure
.input(apiUpdateSshKey)
.mutation(async ({ input }) => {
try {
return await updateSSHKeyById(input);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error to update this ssh key",
cause: error,
});
}
}),
});

View File

@@ -28,6 +28,7 @@ export const users = pgTable("user", {
.notNull()
.$defaultFn(() => new Date().toISOString()),
canCreateProjects: boolean("canCreateProjects").notNull().default(false),
canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false),
canCreateServices: boolean("canCreateServices").notNull().default(false),
canDeleteProjects: boolean("canDeleteProjects").notNull().default(false),
canDeleteServices: boolean("canDeleteServices").notNull().default(false),
@@ -107,6 +108,7 @@ export const apiAssignPermissions = createSchema
canAccessToTraefikFiles: true,
canAccessToDocker: true,
canAccessToAPI: true,
canAccessToSSHKeys: true,
})
.required();

View File

@@ -36,10 +36,9 @@ export const initializePostgres = async () => {
Ports: [
{
TargetPort: 5432,
...(process.env.NODE_ENV === "development"
? { PublishedPort: 5432 }
: {}),
PublishedPort: process.env.NODE_ENV === "development" ? 5432 : 0,
Protocol: "tcp",
PublishMode: "host",
},
],
},

View File

@@ -33,10 +33,9 @@ export const initializeRedis = async () => {
Ports: [
{
TargetPort: 6379,
...(process.env.NODE_ENV === "development"
? { PublishedPort: 6379 }
: {}),
PublishedPort: process.env.NODE_ENV === "development" ? 6379 : 0,
Protocol: "tcp",
PublishMode: "host",
},
],
},

View File

@@ -54,7 +54,11 @@ export const buildApplication = async (
await mechanizeDockerContainer(application);
writeStream.write("Docker Deployed: ✅");
} catch (error) {
writeStream.write("Error ❌");
if (error instanceof Error) {
writeStream.write(`Error ❌\n${error?.message}`);
} else {
writeStream.write("Error ❌");
}
throw error;
} finally {
writeStream.end();

View File

@@ -33,7 +33,9 @@ export const cloneGitRepository = async (
const knownHostsPath = path.join(SSH_PATH, "known_hosts");
try {
await addHostToKnownHosts(customGitUrl);
if (!isHttpOrHttps(customGitUrl)) {
await addHostToKnownHosts(customGitUrl);
}
await recreateDirectory(outputPath);
// const command = `GIT_SSH_COMMAND="ssh -i ${keyPath} -o UserKnownHostsFile=${knownHostsPath}" git clone --branch ${customGitBranch} --depth 1 ${customGitUrl} ${gitCopyPath} --progress`;
// const { stdout, stderr } = await execAsync(command);
@@ -56,6 +58,7 @@ export const cloneGitRepository = async (
customGitBranch,
"--depth",
"1",
"--recurse-submodules",
customGitUrl,
outputPath,
"--progress",
@@ -84,6 +87,11 @@ export const cloneGitRepository = async (
}
};
const isHttpOrHttps = (url: string): boolean => {
const regex = /^https?:\/\//;
return regex.test(url);
};
const addHostToKnownHosts = async (repositoryURL: string) => {
const { domain, port } = sanitizeRepoPathSSH(repositoryURL);
const knownHostsPath = path.join(SSH_PATH, "known_hosts");
@@ -121,7 +129,7 @@ const sanitizeRepoPathSSH = (input: string) => {
return {
user: found.groups?.user ?? "git",
domain: found.groups?.domain,
port: 22,
port: Number(found.groups?.port ?? 22),
owner: found.groups?.owner ?? "",
repo: found.groups?.repo,
get repoPath() {

View File

@@ -21,7 +21,7 @@ export function generate(schema: Schema): Template {
const mounts: Template["mounts"] = [
{
mountPath: "./config.toml",
filePath: "config.toml",
content: `[app]
address = "0.0.0.0:9000"

View File

@@ -23,7 +23,7 @@ export function generate(schema: Schema): Template {
const mounts: Template["mounts"] = [
{
mountPath: "./clickhouse/clickhouse-config.xml",
filePath: "/clickhouse/clickhouse-config.xml",
content: `
<clickhouse>
<logger>
@@ -45,7 +45,7 @@ export function generate(schema: Schema): Template {
`,
},
{
mountPath: "./clickhouse/clickhouse-user-config.xml",
filePath: "/clickhouse/clickhouse-user-config.xml",
content: `
<clickhouse>
<profiles>

View File

@@ -13,7 +13,7 @@ export interface Schema {
export interface Template {
envs: string[];
mounts?: {
mountPath: string;
filePath: string;
content?: string;
}[];
}

View File

@@ -81,6 +81,7 @@ docker service create \
--network dokploy-network \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--mount type=bind,source=/etc/dokploy,target=/etc/dokploy \
--mount type=volume,source=dokploy-docker-config,target=/root/.docker \
--publish published=3000,target=3000,mode=host \
--update-parallelism 1 \
--update-order stop-first \

View File

@@ -65,6 +65,7 @@ docker service create \
--network dokploy-network \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--mount type=bind,source=/etc/dokploy,target=/etc/dokploy \
--mount type=volume,source=dokploy-docker-config,target=/root/.docker \
--publish published=3000,target=3000,mode=host \
--update-parallelism 1 \
--update-order stop-first \

View File

@@ -81,6 +81,7 @@ docker service create \
--network dokploy-network \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--mount type=bind,source=/etc/dokploy,target=/etc/dokploy \
--mount type=volume,source=dokploy-docker-config,target=/root/.docker \
--publish published=3000,target=3000,mode=host \
--update-parallelism 1 \
--update-order stop-first \

View File

@@ -20,7 +20,7 @@
"format-and-lint": "biome check .",
"check": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true",
"format-and-lint:fix": "biome check . --write",
"prepare": "node .husky/install.mjs"
"prepare": "node ./.config/.husky/install.mjs"
},
"devDependencies": {
"dotenv": "16.4.5",

150
pnpm-lock.yaml generated
View File

@@ -39,17 +39,17 @@ importers:
apps/docs:
dependencies:
fumadocs-core:
specifier: 12.2.2
version: 12.2.2(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
specifier: ^12.5.6
version: 12.5.6(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
fumadocs-mdx:
specifier: 8.2.33
version: 8.2.33(fumadocs-core@12.2.2(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
specifier: ^8.2.34
version: 8.2.34(fumadocs-core@12.5.6(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
fumadocs-openapi:
specifier: ^3.1.3
specifier: ^3.3.0
version: 3.3.0
fumadocs-ui:
specifier: 12.2.2
version: 12.2.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.7)
specifier: ^12.5.6
version: 12.5.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.7)
lucide-react:
specifier: ^0.394.0
version: 0.394.0(react@18.3.1)
@@ -114,6 +114,9 @@ importers:
'@codemirror/legacy-modes':
specifier: 6.4.0
version: 6.4.0
'@codemirror/view':
specifier: 6.29.0
version: 6.29.0
'@dokploy/trpc-openapi':
specifier: 0.0.4
version: 0.0.4(@trpc/server@10.45.2)(zod@3.23.8)
@@ -2251,6 +2254,19 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-accordion@1.2.0':
resolution: {integrity: sha512-HJOzSX8dQqtsp/3jVxCU3CXEONF7/2jlGAB28oX8TTw1Dz8JYbEI1UcL8355PuLBE41/IRRMvCw7VkiK/jcUOQ==}
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-alert-dialog@1.1.1':
resolution: {integrity: sha512-wmCoJwj7byuVuiLKqDLlX7ClSUU0vd9sdCeM+2Ls+uf13+cpSJoMgwysHq1SGVVkJj5Xn0XWi1NoRCdkMpr6Mw==}
peerDependencies:
@@ -2316,6 +2332,19 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-collapsible@1.1.0':
resolution: {integrity: sha512-zQY7Epa8sTL0mq4ajSJpjgn2YmCgyrG7RsQgLp3C0LQVkG7+Tf6Pv1CeNWZLyqMjhdPkBa5Lx7wYBeSu7uCSTA==}
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-collection@1.0.3':
resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
peerDependencies:
@@ -5409,15 +5438,15 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
fumadocs-core@12.2.2:
resolution: {integrity: sha512-e8WZ/+iNUuqsxMHWYr/gBXjB5tHVJpeNfNkINyzrwDpatVQ3Ds3sGyvPn/cWkNka4ZYvMbwkjw/7n/0ijsjfRA==}
fumadocs-core@12.5.6:
resolution: {integrity: sha512-sKbVq+Yrf7uLZD/pHojLGwClRxuOyjR1NaIlm/cO9dCaEO6n568NTom/2rEn+jyhII+LbGTJqfIJmktBW6rgNA==}
peerDependencies:
next: '>= 14.1.0'
react: '>= 18'
react-dom: '>= 18'
fumadocs-mdx@8.2.33:
resolution: {integrity: sha512-bKT4CaFMWrPYUqsM2MD6uN4i2XIgZ2mCw9XoMJMpPS3Oq2Eq5MlNs9B5L6ItO7FfckCb9hoCA6LHdT1tVkgtyQ==}
fumadocs-mdx@8.2.34:
resolution: {integrity: sha512-vq7gd16z3fxMCjkjzFSTkqbQXbhZ3ucNvXAWdQxhkbhRbx3EAcmokkbcySsqVdqHPDIm0eGmCV33fQJsku1DgA==}
peerDependencies:
fumadocs-core: 12.x.x
next: '>= 14.1.0'
@@ -5425,8 +5454,8 @@ packages:
fumadocs-openapi@3.3.0:
resolution: {integrity: sha512-a6G1+FoBA4kH2HnjlgwmPpO9z4itrKPRENkVqxJPsOCwpCKdHZc6Tpwogo9CXvEifGqjAvyTbhNPy0N3+YmHLg==}
fumadocs-ui@12.2.2:
resolution: {integrity: sha512-cOUiGk/Bp8Cqd/lBx5LqjbCHO4Ny8qtFItJog6aI5POFVJDJoYuCMv65MLoS/ar7QxIdaiFSw2XYYziZQaLmrQ==}
fumadocs-ui@12.5.6:
resolution: {integrity: sha512-8kYsrSCbRuo2rS09xTAb5HejtH8QDsSlqWGC8k+D9GI4WdAW7kAQCg6k9idnhhP/nq3QOsyMtvpoUGkje91bpQ==}
peerDependencies:
next: '>= 14.1.0'
react: '>= 18'
@@ -6212,10 +6241,10 @@ packages:
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0
lucide-react@0.395.0:
resolution: {integrity: sha512-6hzdNH5723A4FLaYZWpK50iyZH8iS2Jq5zuPRRotOFkhu6kxxJiebVdJ72tCR5XkiIeYFOU5NUawFZOac+VeYw==}
lucide-react@0.414.0:
resolution: {integrity: sha512-Krr/MHg9AWoJc52qx8hyJ64X9++JNfS1wjaJviLM1EP/68VNB7Tv0VMldLCB1aUe6Ka9QxURPhQm/eB6cqOM3A==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
luxon@3.4.4:
resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==}
@@ -10203,18 +10232,17 @@ snapshots:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
'@radix-ui/react-accordion@1.1.2(@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-accordion@1.2.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:
'@babel/runtime': 7.25.0
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-collapsible': 1.0.3(@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-collection': 1.0.3(@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-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-direction': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-id': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-primitive': 1.0.3(@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-use-controllable-state': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/primitive': 1.1.0
'@radix-ui/react-collapsible': 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-collection': 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-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@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)
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -10298,17 +10326,16 @@ snapshots:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
'@radix-ui/react-collapsible@1.0.3(@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-collapsible@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:
'@babel/runtime': 7.25.0
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-id': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-presence': 1.0.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-primitive': 1.0.3(@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-use-controllable-state': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/primitive': 1.1.0
'@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-presence': 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-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)
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
@@ -10328,19 +10355,6 @@ snapshots:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
'@radix-ui/react-collection@1.0.3(@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:
'@babel/runtime': 7.25.0
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-primitive': 1.0.3(@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-slot': 1.0.2(@types/react@18.3.3)(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-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.2.0)
@@ -10529,13 +10543,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.3
'@radix-ui/react-direction@1.0.1(@types/react@18.3.3)(react@18.3.1)':
dependencies:
'@babel/runtime': 7.25.0
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.3
'@radix-ui/react-direction@1.1.0(@types/react@18.3.3)(react@18.2.0)':
dependencies:
react: 18.2.0
@@ -12409,7 +12416,7 @@ snapshots:
'@types/hast@3.0.4':
dependencies:
'@types/unist': 2.0.10
'@types/unist': 3.0.2
'@types/http-cache-semantics@4.0.4': {}
@@ -12429,7 +12436,7 @@ snapshots:
'@types/mdast@4.0.4':
dependencies:
'@types/unist': 2.0.10
'@types/unist': 3.0.2
'@types/mdx@2.0.13': {}
@@ -14033,7 +14040,7 @@ snapshots:
eslint: 8.45.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0)
eslint-plugin-jsx-a11y: 6.9.0(eslint@8.45.0)
eslint-plugin-react: 7.35.0(eslint@8.45.0)
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.45.0)
@@ -14057,7 +14064,7 @@ snapshots:
enhanced-resolve: 5.17.1
eslint: 8.45.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.5
is-core-module: 2.15.0
@@ -14079,7 +14086,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0):
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@@ -14434,7 +14441,7 @@ snapshots:
fsevents@2.3.3:
optional: true
fumadocs-core@12.2.2(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
fumadocs-core@12.5.6(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@formatjs/intl-localematcher': 0.5.4
'@shikijs/rehype': 1.12.0
@@ -14458,13 +14465,13 @@ snapshots:
- '@types/react'
- supports-color
fumadocs-mdx@8.2.33(fumadocs-core@12.2.2(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
fumadocs-mdx@8.2.34(fumadocs-core@12.5.6(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
dependencies:
'@mdx-js/mdx': 3.0.1
cross-spawn: 7.0.3
estree-util-value-to-estree: 3.1.2
fast-glob: 3.3.2
fumadocs-core: 12.2.2(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
fumadocs-core: 12.5.6(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
gray-matter: 4.0.3
next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
zod: 3.23.8
@@ -14479,10 +14486,10 @@ snapshots:
json-schema-to-typescript: 14.1.0
openapi-sampler: 1.5.1
fumadocs-ui@12.2.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.7):
fumadocs-ui@12.5.6(@types/react-dom@18.3.0)(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.7):
dependencies:
'@radix-ui/react-accordion': 1.1.2(@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-collapsible': 1.0.3(@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-accordion': 1.2.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-collapsible': 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-dialog': 1.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-direction': 1.1.0(@types/react@18.3.3)(react@18.3.1)
'@radix-ui/react-popover': 1.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)
@@ -14491,13 +14498,14 @@ snapshots:
'@tailwindcss/typography': 0.5.13(tailwindcss@3.4.7)
class-variance-authority: 0.7.0
cmdk: 1.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)
fumadocs-core: 12.2.2(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
lucide-react: 0.395.0(react@18.3.1)
fumadocs-core: 12.5.6(@types/react@18.3.3)(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
lucide-react: 0.414.0(react@18.3.1)
next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-themes: 0.3.0(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)
react-medium-image-zoom: 5.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
swr: 2.2.5(react@18.3.1)
tailwind-merge: 2.4.0
transitivePeerDependencies:
- '@types/react'
@@ -15357,7 +15365,7 @@ snapshots:
dependencies:
react: 18.3.1
lucide-react@0.395.0(react@18.3.1):
lucide-react@0.414.0(react@18.3.1):
dependencies:
react: 18.3.1