Compare commits

..

20 Commits

Author SHA1 Message Date
Mauricio Siu
2f43f605f3 chore: update version to v0.29.5 in package.json 2026-05-22 17:20:12 -06:00
Mauricio Siu
103e2f70a8 fix: add tls=true label for domains when certificateType is none (#4018) (#4474)
* fix: add tls=true label for compose domains when certificateType is none (#4018)

* test: cover tls=true label for certificateType none, require https

* fix: scope tls fix to compose labels, leave traefik file config unchanged (#4018)
2026-05-22 17:11:05 -06:00
Mauricio Siu
34d38cf90e fix: enable comment toggle shortcut in env variable editor (#4402) (#4473) 2026-05-22 17:00:58 -06:00
mixelburg
f6e6e5cc00 fix: add type="button" to TooltipTrigger in form components to prevent accidental submission (#4422)
Co-authored-by: Maks Pikov <mixelburg@users.noreply.github.com>
2026-05-22 16:50:40 -06:00
Mauricio Siu
b06138b230 fix: prevent webhook deploy crash when commit data lacks modified files (#4470)
shouldDeploy passed undefined/null entries from commit.modified straight
into micromatch, which throws "Expected input to be a string" and fails
every webhook deployment when watch paths are configured. Filter out
non-string values before matching.
2026-05-22 16:46:26 -06:00
Mauricio Siu
af8072d7ad fix: allow square brackets in zip path validation for Next.js dynamic routes (#4468)
* fix: allow square brackets in zip drop path validation for Next.js dynamic routes

ZIP uploads containing Next.js dynamic route files (e.g. app/api/[id]/route.ts,
pages/[slug].tsx) were rejected by readValidDirectory because the path regex
did not include square bracket characters.

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-05-22 16:26:34 -06:00
Francis
6e342ee2f2 fix: automatically converting username to lowercase both in creation of register, and build for extra. (#4382) 2026-05-13 01:09:47 -06:00
Nahidujjaman Hridoy
ef0cf9bd02 fix: responsive layout (#4391)
Signed-off-by: Nahidujjaman Hridoy <hridoyboss12@gmail.com>
2026-05-13 01:03:59 -06:00
Volodymyr Kravchuk
8d88a34a64 fix: copy Dokploy server IP when clicking server badge (#4390)
* fix: copy Dokploy server IP when clicking server badge

When a service runs on the local Dokploy server (no remote server),
clicking the server badge did nothing because `data.server` is null.
Now falls back to the server IP from settings so the badge always
copies an IP address.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(copy-ip): implement IP address copying functionality across database service components

- Added the ability to copy the server IP address to the clipboard when clicking the server badge in various database service components (Libsql, MariaDB, MongoDB, MySQL, PostgreSQL, Redis).
- Integrated the `copy-to-clipboard` library and `sonner` for user feedback upon successful copy action.
- Ensured fallback to the server IP from settings when the service data is not available, enhancing user experience and functionality.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>
2026-05-13 01:03:29 -06:00
Mauricio Siu
a50f958a6f feat(settings): add copy button to server IP in web server settings (#4397) 2026-05-13 00:54:20 -06:00
Mauricio Siu
1fdbe87d84 feat(user): implement session cleanup on user update
- Added functionality to delete old sessions when a user updates their password, ensuring that only the current session remains active.
- This change enhances security by preventing unauthorized access from previous sessions after a password change.

Close here https://github.com/Dokploy/dokploy/security/advisories/GHSA-rr9m-w87g-46f3
2026-05-13 00:49:32 -06:00
Mauricio Siu
67278d8783 feat(organization): prevent inviting users with owner role
- Added validation to prevent users from being invited with the owner role in the organization and user routers.
- Implemented TRPCError responses to ensure proper error handling when attempting to assign the owner role.
This change enhances role management and security within the organization structure.

https://github.com/Dokploy/dokploy/security/advisories/GHSA-fm9p-wmpw-gxjh
2026-05-13 00:42:29 -06:00
Mauricio Siu
aff200f84f feat(deployment): add server access validation for deployment actions
- Implemented server access validation in deployment procedures to ensure users can only access deployments associated with their active organization.
- Added checks to throw an UNAUTHORIZED error if a user attempts to access a deployment linked to a server outside their organization.

This enhancement improves security and access control within the deployment management system.
2026-05-13 00:09:47 -06:00
Mauricio Siu
558d809871 feat(deployment): add readLogs procedure to fetch deployment logs
- Introduced a new `readLogs` procedure that allows users to retrieve logs for a specific deployment by providing the deployment ID and an optional tail parameter.
- Implemented permission checks to ensure users have access to the requested logs.
- Enhanced log retrieval for both cloud and non-cloud environments, utilizing appropriate commands based on the server context.

Resolve https://github.com/Dokploy/mcp/issues/14
2026-05-13 00:04:26 -06:00
Mauricio Siu
f8fcf68909 Enhance version synchronization workflow to include SDK repository
- Updated the GitHub Actions workflow to sync versioning across MCP, CLI, and SDK repositories.
- Added steps to bump the version in the SDK repository and regenerate tools from the latest OpenAPI spec.
- Improved commit message formatting to include source and release information for all repositories.
- Ensured successful synchronization messages for each repository after the version update.
2026-05-12 13:26:09 -06:00
Mauricio Siu
7a568aadac Merge pull request #4395 from Dokploy/feat/import-compose-from-base64
feat(compose): add import from base64 in create service dropdown
2026-05-12 13:13:33 -06:00
autofix-ci[bot]
63e33a29cc [autofix.ci] apply automated fixes 2026-05-12 19:12:46 +00:00
Mauricio Siu
754774ea02 feat(compose): add import from base64 in create service dropdown
Adds an "Import" option to the Create Service dropdown that lets users
paste a base64-encoded compose export, preview the template (compose YAML,
domains, envs, mounts) before confirming, and create the service only on
confirm. Adds a `previewTemplate` tRPC procedure that processes the base64
without touching the DB, with server access validation via session.
2026-05-12 13:12:14 -06:00
Mauricio Siu
a714e0f83f Merge pull request #4394 from ngenohkevin/fix/migrate-auth-secret-exit-on-empty
fix(migrate-auth-secret): exit cleanly when there are no 2FA records
2026-05-12 13:04:23 -06:00
ngenohkevin
9f10f0f4e9 fix(migrate-auth-secret): exit cleanly when there are no 2FA records
The empty-records branch of `main()` returned without calling
`process.exit(0)`, leaving the Drizzle Postgres connection pool
holding the event loop open. The `migrate-auth-secret` process
then hangs indefinitely after printing "No 2FA records found,
nothing to migrate." causing the upstream `0.29.3.sh` security
migration script (which calls this via `docker exec`) to never
reach its final `docker service update` step that mounts the new
Docker Secret. Operators end up with the new secret created but
the dokploy service still configured with the hardcoded
`BETTER_AUTH_SECRET`, while believing the migration completed.

Match the success branch a few lines below which already does
`process.exit(0)`, and the pattern used in sibling scripts
`reset-password.ts` and `reset-2fa.ts`.

Closes #4392
2026-05-12 21:35:02 +03:00
57 changed files with 258 additions and 25626 deletions

View File

@@ -1,52 +0,0 @@
import { getBuildComposeCommand } from "@dokploy/server/utils/builders/compose";
import { describe, expect, it, vi } from "vitest";
// Isolate the command builder from the compose-file I/O performed by
// writeDomainsToCompose; we only care about the docker invocation it emits.
vi.mock("@dokploy/server/utils/docker/domain", () => ({
writeDomainsToCompose: vi.fn().mockResolvedValue(""),
}));
const baseCompose = {
appName: "my-app",
sourceType: "raw",
command: "",
composePath: "docker-compose.yml",
composeType: "stack",
isolatedDeployment: false,
randomize: false,
suffix: "",
serverId: null,
env: "",
mounts: [],
domains: [],
environment: { project: { env: "" }, env: "" },
} as unknown as Parameters<typeof getBuildComposeCommand>[0];
// Regression coverage for #4401: the deploy command runs under `env -i`, which
// clears the environment except for the vars listed explicitly. HOME must be
// preserved so docker can resolve ~/.docker/config.json — otherwise
// `docker stack deploy --with-registry-auth` ships no credentials to the swarm
// and private-registry images fail to pull.
describe("getBuildComposeCommand registry auth (#4401)", () => {
it("preserves HOME for swarm stack deploys", async () => {
const command = await getBuildComposeCommand({
...baseCompose,
composeType: "stack",
});
expect(command).toContain("stack deploy");
expect(command).toContain("--with-registry-auth");
expect(command).toContain('env -i PATH="$PATH" HOME="$HOME"');
});
it("preserves HOME for docker compose deploys", async () => {
const command = await getBuildComposeCommand({
...baseCompose,
composeType: "docker-compose",
});
expect(command).toContain("compose -p my-app");
expect(command).toContain('env -i PATH="$PATH" HOME="$HOME"');
});
});

View File

@@ -58,7 +58,7 @@ beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
}); });
describe("owner and admin bypass enterprise resources", () => { describe("static roles bypass enterprise resources", () => {
it("owner bypasses deployment.read", async () => { it("owner bypasses deployment.read", async () => {
memberToReturn = mockMemberData("owner"); memberToReturn = mockMemberData("owner");
await expect( await expect(
@@ -73,8 +73,15 @@ describe("owner and admin bypass enterprise resources", () => {
).resolves.toBeUndefined(); ).resolves.toBeUndefined();
}); });
it("owner bypasses multiple enterprise permissions at once", async () => { it("member bypasses schedule.delete", async () => {
memberToReturn = mockMemberData("owner"); memberToReturn = mockMemberData("member");
await expect(
checkPermission(ctx, { schedule: ["delete"] }),
).resolves.toBeUndefined();
});
it("member bypasses multiple enterprise permissions at once", async () => {
memberToReturn = mockMemberData("member");
await expect( await expect(
checkPermission(ctx, { checkPermission(ctx, {
deployment: ["read"], deployment: ["read"],
@@ -85,55 +92,6 @@ describe("owner and admin bypass enterprise resources", () => {
}); });
}); });
describe("member is denied org-level enterprise resources (CVE: bypass via staticRoles)", () => {
it("member is denied registry.read", async () => {
memberToReturn = mockMemberData("member");
await expect(
checkPermission(ctx, { registry: ["read"] }),
).rejects.toThrow();
});
it("member is denied certificate.read", async () => {
memberToReturn = mockMemberData("member");
await expect(
checkPermission(ctx, { certificate: ["read"] }),
).rejects.toThrow();
});
it("member is denied destination.read", async () => {
memberToReturn = mockMemberData("member");
await expect(
checkPermission(ctx, { destination: ["read"] }),
).rejects.toThrow();
});
it("member is denied notification.read", async () => {
memberToReturn = mockMemberData("member");
await expect(
checkPermission(ctx, { notification: ["read"] }),
).rejects.toThrow();
});
it("member is denied auditLog.read", async () => {
memberToReturn = mockMemberData("member");
await expect(
checkPermission(ctx, { auditLog: ["read"] }),
).rejects.toThrow();
});
it("member is denied server.read", async () => {
memberToReturn = mockMemberData("member");
await expect(checkPermission(ctx, { server: ["read"] })).rejects.toThrow();
});
it("member is denied registry.create", async () => {
memberToReturn = mockMemberData("member");
await expect(
checkPermission(ctx, { registry: ["create"] }),
).rejects.toThrow();
});
});
describe("static roles validate free-tier resources", () => { describe("static roles validate free-tier resources", () => {
it("owner passes project.create", async () => { it("owner passes project.create", async () => {
memberToReturn = mockMemberData("owner"); memberToReturn = mockMemberData("owner");

View File

@@ -65,8 +65,6 @@ const baseSettings: WebServerSettings = {
cleanupCacheApplications: false, cleanupCacheApplications: false,
cleanupCacheOnCompose: false, cleanupCacheOnCompose: false,
cleanupCacheOnPreviews: false, cleanupCacheOnPreviews: false,
remoteServersOnly: false,
enforceSSO: false,
createdAt: null, createdAt: null,
updatedAt: new Date(), updatedAt: new Date(),
}; };

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { CheckIcon, ChevronsUpDown, HelpCircle, X } from "lucide-react"; import { CheckIcon, ChevronsUpDown, HelpCircle, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -6,6 +5,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { BitbucketIcon } from "@/components/icons/data-tools-icons"; import { BitbucketIcon } from "@/components/icons/data-tools-icons";
import { AlertBlock } from "@/components/shared/alert-block"; import { AlertBlock } from "@/components/shared/alert-block";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { HelpCircle, KeyRoundIcon, LockIcon, X } from "lucide-react"; import { HelpCircle, KeyRoundIcon, LockIcon, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -7,6 +6,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { GitIcon } from "@/components/icons/data-tools-icons"; import { GitIcon } from "@/components/icons/data-tools-icons";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react"; import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -6,6 +5,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { GiteaIcon } from "@/components/icons/data-tools-icons"; import { GiteaIcon } from "@/components/icons/data-tools-icons";
import { AlertBlock } from "@/components/shared/alert-block"; import { AlertBlock } from "@/components/shared/alert-block";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react"; import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -6,6 +5,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { GithubIcon } from "@/components/icons/data-tools-icons"; import { GithubIcon } from "@/components/icons/data-tools-icons";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react"; import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -6,6 +5,7 @@ import { useEffect, useMemo } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { GitlabIcon } from "@/components/icons/data-tools-icons"; import { GitlabIcon } from "@/components/icons/data-tools-icons";
import { AlertBlock } from "@/components/shared/alert-block"; import { AlertBlock } from "@/components/shared/alert-block";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { CheckIcon, ChevronsUpDown, X } from "lucide-react"; import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -6,6 +5,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { BitbucketIcon } from "@/components/icons/data-tools-icons"; import { BitbucketIcon } from "@/components/icons/data-tools-icons";
import { AlertBlock } from "@/components/shared/alert-block"; import { AlertBlock } from "@/components/shared/alert-block";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { HelpCircle, KeyRoundIcon, LockIcon, X } from "lucide-react"; import { HelpCircle, KeyRoundIcon, LockIcon, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -7,6 +6,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { GitIcon } from "@/components/icons/data-tools-icons"; import { GitIcon } from "@/components/icons/data-tools-icons";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react"; import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -6,6 +5,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { GiteaIcon } from "@/components/icons/data-tools-icons"; import { GiteaIcon } from "@/components/icons/data-tools-icons";
import { AlertBlock } from "@/components/shared/alert-block"; import { AlertBlock } from "@/components/shared/alert-block";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";

View File

@@ -1,4 +1,3 @@
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { CheckIcon, ChevronsUpDown, X } from "lucide-react"; import { CheckIcon, ChevronsUpDown, X } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
@@ -6,6 +5,7 @@ import { useEffect, useMemo } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
import { GitlabIcon } from "@/components/icons/data-tools-icons"; import { GitlabIcon } from "@/components/icons/data-tools-icons";
import { AlertBlock } from "@/components/shared/alert-block"; import { AlertBlock } from "@/components/shared/alert-block";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";

View File

@@ -71,9 +71,6 @@ interface Props {
export const AddApplication = ({ environmentId, projectName }: Props) => { export const AddApplication = ({ environmentId, projectName }: Props) => {
const utils = api.useUtils(); const utils = api.useUtils();
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { data: webServerSettings } =
api.settings.getWebServerSettings.useQuery();
const showLocalOption = !isCloud && !webServerSettings?.remoteServersOnly;
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const slug = slugify(projectName); const slug = slugify(projectName);
const { data: servers } = api.server.withSSHKey.useQuery(); const { data: servers } = api.server.withSSHKey.useQuery();
@@ -174,8 +171,7 @@ export const AddApplication = ({ environmentId, projectName }: Props) => {
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<FormLabel className="break-all w-fit flex flex-row gap-1 items-center"> <FormLabel className="break-all w-fit flex flex-row gap-1 items-center">
Select a Server{" "} Select a Server {!isCloud ? "(Optional)" : ""}
{showLocalOption ? "(Optional)" : ""}
<HelpCircle className="size-4 text-muted-foreground" /> <HelpCircle className="size-4 text-muted-foreground" />
</FormLabel> </FormLabel>
</TooltipTrigger> </TooltipTrigger>
@@ -195,19 +191,17 @@ export const AddApplication = ({ environmentId, projectName }: Props) => {
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={ defaultValue={
field.value || (showLocalOption ? "dokploy" : undefined) field.value || (!isCloud ? "dokploy" : undefined)
} }
> >
<SelectTrigger> <SelectTrigger>
<SelectValue <SelectValue
placeholder={ placeholder={!isCloud ? "Dokploy" : "Select a Server"}
showLocalOption ? "Dokploy" : "Select a Server"
}
/> />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
{showLocalOption && ( {!isCloud && (
<SelectItem value="dokploy"> <SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full"> <span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span> <span>Dokploy</span>
@@ -231,8 +225,7 @@ export const AddApplication = ({ environmentId, projectName }: Props) => {
</SelectItem> </SelectItem>
))} ))}
<SelectLabel> <SelectLabel>
Servers ( Servers ({servers?.length + (!isCloud ? 1 : 0)})
{servers?.length + (showLocalOption ? 1 : 0)})
</SelectLabel> </SelectLabel>
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>

View File

@@ -74,9 +74,6 @@ export const AddCompose = ({ environmentId, projectName }: Props) => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const slug = slugify(projectName); const slug = slugify(projectName);
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { data: webServerSettings } =
api.settings.getWebServerSettings.useQuery();
const showLocalOption = !isCloud && !webServerSettings?.remoteServersOnly;
const { data: servers } = api.server.withSSHKey.useQuery(); const { data: servers } = api.server.withSSHKey.useQuery();
const { mutateAsync, isPending, error, isError } = const { mutateAsync, isPending, error, isError } =
api.compose.create.useMutation(); api.compose.create.useMutation();
@@ -185,8 +182,7 @@ export const AddCompose = ({ environmentId, projectName }: Props) => {
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<FormLabel className="break-all w-fit flex flex-row gap-1 items-center"> <FormLabel className="break-all w-fit flex flex-row gap-1 items-center">
Select a Server{" "} Select a Server {!isCloud ? "(Optional)" : ""}
{showLocalOption ? "(Optional)" : ""}
<HelpCircle className="size-4 text-muted-foreground" /> <HelpCircle className="size-4 text-muted-foreground" />
</FormLabel> </FormLabel>
</TooltipTrigger> </TooltipTrigger>
@@ -206,19 +202,17 @@ export const AddCompose = ({ environmentId, projectName }: Props) => {
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={ defaultValue={
field.value || (showLocalOption ? "dokploy" : undefined) field.value || (!isCloud ? "dokploy" : undefined)
} }
> >
<SelectTrigger> <SelectTrigger>
<SelectValue <SelectValue
placeholder={ placeholder={!isCloud ? "Dokploy" : "Select a Server"}
showLocalOption ? "Dokploy" : "Select a Server"
}
/> />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
{showLocalOption && ( {!isCloud && (
<SelectItem value="dokploy"> <SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full"> <span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span> <span>Dokploy</span>
@@ -242,8 +236,7 @@ export const AddCompose = ({ environmentId, projectName }: Props) => {
</SelectItem> </SelectItem>
))} ))}
<SelectLabel> <SelectLabel>
Servers ( Servers ({servers?.length + (!isCloud ? 1 : 0)})
{servers?.length + (showLocalOption ? 1 : 0)})
</SelectLabel> </SelectLabel>
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>

View File

@@ -219,9 +219,6 @@ export const AddDatabase = ({ environmentId, projectName }: Props) => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const slug = slugify(projectName); const slug = slugify(projectName);
const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery();
const { data: webServerSettings } =
api.settings.getWebServerSettings.useQuery();
const showLocalOption = !isCloud && !webServerSettings?.remoteServersOnly;
const { data: servers } = api.server.withSSHKey.useQuery(); const { data: servers } = api.server.withSSHKey.useQuery();
const libsqlMutation = api.libsql.create.useMutation(); const libsqlMutation = api.libsql.create.useMutation();
const mariadbMutation = api.mariadb.create.useMutation(); const mariadbMutation = api.mariadb.create.useMutation();
@@ -473,20 +470,19 @@ export const AddDatabase = ({ environmentId, projectName }: Props) => {
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={ defaultValue={
field.value || field.value || (!isCloud ? "dokploy" : undefined)
(showLocalOption ? "dokploy" : undefined)
} }
> >
<SelectTrigger> <SelectTrigger>
<SelectValue <SelectValue
placeholder={ placeholder={
showLocalOption ? "Dokploy" : "Select a Server" !isCloud ? "Dokploy" : "Select a Server"
} }
/> />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
{showLocalOption && ( {!isCloud && (
<SelectItem value="dokploy"> <SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full"> <span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span> <span>Dokploy</span>
@@ -505,8 +501,7 @@ export const AddDatabase = ({ environmentId, projectName }: Props) => {
</SelectItem> </SelectItem>
))} ))}
<SelectLabel> <SelectLabel>
Servers ( Servers ({servers?.length + (!isCloud ? 1 : 0)})
{servers?.length + (showLocalOption ? 1 : 0)})
</SelectLabel> </SelectLabel>
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>

View File

@@ -1,48 +0,0 @@
import { HelpCircle } from "lucide-react";
import { toast } from "sonner";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { api } from "@/utils/api";
export const ToggleEnforceSSO = () => {
const { data, refetch } = api.settings.getWebServerSettings.useQuery();
const { mutateAsync } = api.settings.updateEnforceSSO.useMutation();
const handleToggle = async (checked: boolean) => {
try {
await mutateAsync({ enforceSSO: checked });
await refetch();
toast.success("Enforce SSO updated");
} catch {
toast.error("Error updating Enforce SSO");
}
};
return (
<div className="flex items-center gap-4">
<Switch checked={!!data?.enforceSSO} onCheckedChange={handleToggle} />
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Label className="text-primary flex items-center gap-1.5 cursor-pointer">
Enforce SSO
<HelpCircle className="size-4 text-muted-foreground" />
</Label>
</TooltipTrigger>
<TooltipContent side="top" className="max-w-sm">
<p>
When enabled, the email/password login form is hidden and users
must sign in exclusively through SSO.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
};

View File

@@ -1,53 +0,0 @@
import { HelpCircle } from "lucide-react";
import { toast } from "sonner";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { api } from "@/utils/api";
export const ToggleRemoteServersOnly = () => {
const { data, refetch } = api.settings.getWebServerSettings.useQuery();
const { mutateAsync } = api.settings.updateRemoteServersOnly.useMutation();
const handleToggle = async (checked: boolean) => {
try {
await mutateAsync({ remoteServersOnly: checked });
await refetch();
toast.success("Remote Servers Only updated");
} catch {
toast.error("Error updating Remote Servers Only");
}
};
return (
<div className="flex items-center gap-4">
<Switch
checked={!!data?.remoteServersOnly}
onCheckedChange={handleToggle}
/>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Label className="text-primary flex items-center gap-1.5 cursor-pointer">
Remote Servers Only
<HelpCircle className="size-4 text-muted-foreground" />
</Label>
</TooltipTrigger>
<TooltipContent side="top" className="max-w-sm">
<p>
When enabled, all services (applications, databases, compose) must
be deployed to a remote server. Deploying directly to the Dokploy
host VM is not allowed.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
};

View File

@@ -131,10 +131,10 @@ export const ShowServers = () => {
className="relative hover:shadow-lg transition-shadow flex flex-col bg-transparent" className="relative hover:shadow-lg transition-shadow flex flex-col bg-transparent"
> >
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between">
<div className="flex min-w-0 items-center gap-2"> <div className="flex items-center gap-2">
<ServerIcon className="size-5 shrink-0 text-muted-foreground" /> <ServerIcon className="size-5 text-muted-foreground" />
<CardTitle className="text-lg break-words min-w-0"> <CardTitle className="text-lg">
{server.name} {server.name}
</CardTitle> </CardTitle>
</div> </div>
@@ -145,7 +145,7 @@ export const ShowServers = () => {
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Button <Button
variant="ghost" variant="ghost"
className="h-8 w-8 shrink-0 p-0" className="h-8 w-8 p-0"
> >
<span className="sr-only"> <span className="sr-only">
More options More options

View File

@@ -1,6 +1,4 @@
import copy from "copy-to-clipboard";
import { CopyIcon, ServerIcon } from "lucide-react"; import { CopyIcon, ServerIcon } from "lucide-react";
import { toast } from "sonner";
import { import {
Card, Card,
CardContent, CardContent,
@@ -9,6 +7,8 @@ import {
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import copy from "copy-to-clipboard";
import { toast } from "sonner";
import { ShowDokployActions } from "./servers/actions/show-dokploy-actions"; import { ShowDokployActions } from "./servers/actions/show-dokploy-actions";
import { ShowStorageActions } from "./servers/actions/show-storage-actions"; import { ShowStorageActions } from "./servers/actions/show-storage-actions";
import { ShowTraefikActions } from "./servers/actions/show-traefik-actions"; import { ShowTraefikActions } from "./servers/actions/show-traefik-actions";

View File

@@ -29,15 +29,10 @@ type SSOEmailForm = z.infer<typeof ssoEmailSchema>;
interface SignInWithSSOProps { interface SignInWithSSOProps {
/** Content shown when SSO is collapsed (e.g. email/password form) */ /** Content shown when SSO is collapsed (e.g. email/password form) */
children?: React.ReactNode; children: React.ReactNode;
/** When true, SSO is the only option — no fallback to email/password */
enforce?: boolean;
} }
export function SignInWithSSO({ export function SignInWithSSO({ children }: SignInWithSSOProps) {
children,
enforce = false,
}: SignInWithSSOProps) {
const [expanded, setExpanded] = useState(false); const [expanded, setExpanded] = useState(false);
const form = useForm<SSOEmailForm>({ const form = useForm<SSOEmailForm>({
@@ -77,7 +72,7 @@ export function SignInWithSSO({
<LogIn className="mr-2 size-4" /> <LogIn className="mr-2 size-4" />
Sign in with SSO Sign in with SSO
</Button> </Button>
{!enforce && children} {children}
</div> </div>
); );
} }
@@ -118,15 +113,13 @@ export function SignInWithSSO({
</FormItem> </FormItem>
)} )}
/> />
{!enforce && ( <button
<button type="button"
type="button" onClick={() => setExpanded(false)}
onClick={() => setExpanded(false)} className="text-xs text-muted-foreground hover:underline"
className="text-xs text-muted-foreground hover:underline" >
> Use email and password instead
Use email and password instead </button>
</button>
)}
</form> </form>
</Form> </Form>
</div> </div>

View File

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

View File

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

View File

@@ -1,11 +0,0 @@
ALTER TABLE "schedule" DROP CONSTRAINT "schedule_userId_user_id_fk";
--> statement-breakpoint
ALTER TABLE "schedule" ADD COLUMN "organizationId" text;--> statement-breakpoint
ALTER TABLE "schedule" ADD CONSTRAINT "schedule_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
UPDATE "schedule" s
SET "organizationId" = m."organization_id"
FROM "member" m
WHERE s."scheduleType" = 'dokploy-server'
AND s."userId" = m."user_id"
AND m."role" = 'owner';--> statement-breakpoint
ALTER TABLE "schedule" DROP COLUMN "userId";

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1170,27 +1170,6 @@
"when": 1778303519111, "when": 1778303519111,
"tag": "0166_nosy_slapstick", "tag": "0166_nosy_slapstick",
"breakpoints": true "breakpoints": true
},
{
"idx": 167,
"version": "7",
"when": 1780122576214,
"tag": "0167_fresh_goliath",
"breakpoints": true
},
{
"idx": 168,
"version": "7",
"when": 1780122833339,
"tag": "0168_long_justice",
"breakpoints": true
},
{
"idx": 169,
"version": "7",
"when": 1780127552074,
"tag": "0169_parched_johnny_storm",
"breakpoints": true
} }
] ]
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "dokploy", "name": "dokploy",
"version": "v0.29.7", "version": "v0.29.5",
"private": true, "private": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"type": "module", "type": "module",
@@ -123,7 +123,7 @@
"lucide-react": "^0.469.0", "lucide-react": "^0.469.0",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"nanoid": "3.3.11", "nanoid": "3.3.11",
"next": "16.2.6", "next": "^16.2.0",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"nextjs-toploader": "^3.9.17", "nextjs-toploader": "^3.9.17",
"node-os-utils": "2.0.1", "node-os-utils": "2.0.1",

View File

@@ -1,6 +1,6 @@
import copy from "copy-to-clipboard";
import { validateRequest } from "@dokploy/server/lib/auth"; import { validateRequest } from "@dokploy/server/lib/auth";
import { createServerSideHelpers } from "@trpc/react-query/server"; import { createServerSideHelpers } from "@trpc/react-query/server";
import copy from "copy-to-clipboard";
import { HelpCircle, ServerOff } from "lucide-react"; import { HelpCircle, ServerOff } from "lucide-react";
import type { import type {
GetServerSidePropsContext, GetServerSidePropsContext,
@@ -10,8 +10,8 @@ import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { type ReactElement, useState } from "react"; import { type ReactElement, useState } from "react";
import { toast } from "sonner";
import superjson from "superjson"; import superjson from "superjson";
import { toast } from "sonner";
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { DeleteService } from "@/components/dashboard/compose/delete-service";

View File

@@ -1,6 +1,6 @@
import copy from "copy-to-clipboard";
import { validateRequest } from "@dokploy/server/lib/auth"; import { validateRequest } from "@dokploy/server/lib/auth";
import { createServerSideHelpers } from "@trpc/react-query/server"; import { createServerSideHelpers } from "@trpc/react-query/server";
import copy from "copy-to-clipboard";
import { HelpCircle, ServerOff } from "lucide-react"; import { HelpCircle, ServerOff } from "lucide-react";
import type { import type {
GetServerSidePropsContext, GetServerSidePropsContext,
@@ -10,8 +10,8 @@ import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { type ReactElement, useState } from "react"; import { type ReactElement, useState } from "react";
import { toast } from "sonner";
import superjson from "superjson"; import superjson from "superjson";
import { toast } from "sonner";
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { DeleteService } from "@/components/dashboard/compose/delete-service";

View File

@@ -1,6 +1,6 @@
import copy from "copy-to-clipboard";
import { validateRequest } from "@dokploy/server/lib/auth"; import { validateRequest } from "@dokploy/server/lib/auth";
import { createServerSideHelpers } from "@trpc/react-query/server"; import { createServerSideHelpers } from "@trpc/react-query/server";
import copy from "copy-to-clipboard";
import { HelpCircle, ServerOff } from "lucide-react"; import { HelpCircle, ServerOff } from "lucide-react";
import type { import type {
GetServerSidePropsContext, GetServerSidePropsContext,
@@ -10,8 +10,8 @@ import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { type ReactElement, useState } from "react"; import { type ReactElement, useState } from "react";
import { toast } from "sonner";
import superjson from "superjson"; import superjson from "superjson";
import { toast } from "sonner";
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { DeleteService } from "@/components/dashboard/compose/delete-service";

View File

@@ -10,8 +10,8 @@ import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { type ReactElement, useState } from "react"; import { type ReactElement, useState } from "react";
import { toast } from "sonner";
import superjson from "superjson"; import superjson from "superjson";
import { toast } from "sonner";
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { DeleteService } from "@/components/dashboard/compose/delete-service";

View File

@@ -1,6 +1,6 @@
import copy from "copy-to-clipboard";
import { validateRequest } from "@dokploy/server/lib/auth"; import { validateRequest } from "@dokploy/server/lib/auth";
import { createServerSideHelpers } from "@trpc/react-query/server"; import { createServerSideHelpers } from "@trpc/react-query/server";
import copy from "copy-to-clipboard";
import { HelpCircle, ServerOff } from "lucide-react"; import { HelpCircle, ServerOff } from "lucide-react";
import type { import type {
GetServerSidePropsContext, GetServerSidePropsContext,
@@ -10,8 +10,8 @@ import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { type ReactElement, useState } from "react"; import { type ReactElement, useState } from "react";
import { toast } from "sonner";
import superjson from "superjson"; import superjson from "superjson";
import { toast } from "sonner";
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { DeleteService } from "@/components/dashboard/compose/delete-service";

View File

@@ -1,6 +1,6 @@
import copy from "copy-to-clipboard";
import { validateRequest } from "@dokploy/server/lib/auth"; import { validateRequest } from "@dokploy/server/lib/auth";
import { createServerSideHelpers } from "@trpc/react-query/server"; import { createServerSideHelpers } from "@trpc/react-query/server";
import copy from "copy-to-clipboard";
import { HelpCircle, ServerOff } from "lucide-react"; import { HelpCircle, ServerOff } from "lucide-react";
import type { import type {
GetServerSidePropsContext, GetServerSidePropsContext,
@@ -10,8 +10,8 @@ import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { type ReactElement, useState } from "react"; import { type ReactElement, useState } from "react";
import { toast } from "sonner";
import superjson from "superjson"; import superjson from "superjson";
import { toast } from "sonner";
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { DeleteService } from "@/components/dashboard/compose/delete-service";

View File

@@ -5,13 +5,18 @@ import type { ReactElement } from "react";
import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules"; import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules";
import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { api } from "@/utils/api";
function SchedulesPage() { function SchedulesPage() {
const { data: user } = api.user.get.useQuery();
return ( return (
<div className="w-full"> <div className="w-full">
<Card className="h-full bg-sidebar p-2.5 rounded-xl max-w-8xl mx-auto min-h-[45vh]"> <Card className="h-full bg-sidebar p-2.5 rounded-xl max-w-8xl mx-auto min-h-[45vh]">
<div className="rounded-xl bg-background shadow-md h-full"> <div className="rounded-xl bg-background shadow-md h-full">
<ShowSchedules scheduleType="dokploy-server" id="dokploy-server" /> <ShowSchedules
scheduleType="dokploy-server"
id={user?.user.id || ""}
/>
</div> </div>
</Card> </Card>
</div> </div>

View File

@@ -1,27 +1,15 @@
import { IS_CLOUD, validateRequest } from "@dokploy/server"; import { validateRequest } from "@dokploy/server";
import { createServerSideHelpers } from "@trpc/react-query/server"; import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext } from "next"; import type { GetServerSidePropsContext } from "next";
import type { ReactElement } from "react"; import type { ReactElement } from "react";
import superjson from "superjson"; import superjson from "superjson";
import { ToggleEnforceSSO } from "@/components/dashboard/settings/servers/actions/toggle-enforce-sso";
import { ToggleRemoteServersOnly } from "@/components/dashboard/settings/servers/actions/toggle-remote-servers-only";
import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { EnterpriseFeatureGate } from "@/components/proprietary/enterprise-feature-gate"; import { EnterpriseFeatureGate } from "@/components/proprietary/enterprise-feature-gate";
import { SSOSettings } from "@/components/proprietary/sso/sso-settings"; import { SSOSettings } from "@/components/proprietary/sso/sso-settings";
import { import { Card } from "@/components/ui/card";
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { appRouter } from "@/server/api/root"; import { appRouter } from "@/server/api/root";
interface Props { const Page = () => {
isCloud: boolean;
}
const Page = ({ isCloud }: Props) => {
return ( return (
<div className="w-full"> <div className="w-full">
<div className="h-full rounded-xl max-w-5xl mx-auto flex flex-col gap-4"> <div className="h-full rounded-xl max-w-5xl mx-auto flex flex-col gap-4">
@@ -41,33 +29,6 @@ const Page = ({ isCloud }: Props) => {
</div> </div>
</div> </div>
</Card> </Card>
{!isCloud && (
<Card className="h-full bg-sidebar p-2.5 rounded-xl mx-auto w-full">
<div className="rounded-xl bg-background shadow-md">
<EnterpriseFeatureGate
lockedProps={{
title: "Self-hosted Restrictions",
description:
"Deployment and authentication restrictions are part of Dokploy Enterprise. Add a valid license to configure them.",
ctaLabel: "Go to License",
}}
>
<CardHeader>
<CardTitle className="text-xl">
Self-hosted Restrictions
</CardTitle>
<CardDescription>
Control deployment targets and authentication behavior.
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<ToggleRemoteServersOnly />
<ToggleEnforceSSO />
</CardContent>
</EnterpriseFeatureGate>
</div>
</Card>
)}
</div> </div>
</div> </div>
); );
@@ -115,7 +76,6 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
return { return {
props: { props: {
trpcState: helpers.dehydrate(), trpcState: helpers.dehydrate(),
isCloud: IS_CLOUD,
}, },
}; };
} }

View File

@@ -1,8 +1,4 @@
import { import { IS_CLOUD, isAdminPresent } from "@dokploy/server";
getWebServerSettings,
IS_CLOUD,
isAdminPresent,
} from "@dokploy/server";
import { validateRequest } from "@dokploy/server/lib/auth"; import { validateRequest } from "@dokploy/server/lib/auth";
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
import { REGEXP_ONLY_DIGITS } from "input-otp"; import { REGEXP_ONLY_DIGITS } from "input-otp";
@@ -56,9 +52,8 @@ type LoginForm = z.infer<typeof LoginSchema>;
interface Props { interface Props {
IS_CLOUD: boolean; IS_CLOUD: boolean;
enforceSSO: boolean;
} }
export default function Home({ IS_CLOUD, enforceSSO }: Props) { export default function Home({ IS_CLOUD }: Props) {
const router = useRouter(); const router = useRouter();
const { config: whitelabeling } = useWhitelabelingPublic(); const { config: whitelabeling } = useWhitelabelingPublic();
const { data: showSignInWithSSO } = api.sso.showSignInWithSSO.useQuery(); const { data: showSignInWithSSO } = api.sso.showSignInWithSSO.useQuery();
@@ -252,9 +247,7 @@ export default function Home({ IS_CLOUD, enforceSSO }: Props) {
<CardContent className="p-0"> <CardContent className="p-0">
{!isTwoFactor ? ( {!isTwoFactor ? (
<> <>
{enforceSSO ? ( {showSignInWithSSO ? (
<SignInWithSSO enforce />
) : showSignInWithSSO ? (
<SignInWithSSO>{loginContent}</SignInWithSSO> <SignInWithSSO>{loginContent}</SignInWithSSO>
) : ( ) : (
loginContent loginContent
@@ -424,7 +417,6 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
return { return {
props: { props: {
IS_CLOUD: IS_CLOUD, IS_CLOUD: IS_CLOUD,
enforceSSO: false,
}, },
}; };
} }
@@ -450,12 +442,9 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
}; };
} }
const webServerSettings = await getWebServerSettings();
return { return {
props: { props: {
hasAdmin, hasAdmin,
enforceSSO: webServerSettings?.enforceSSO ?? false,
}, },
}; };
} }

View File

@@ -9,7 +9,6 @@ import {
getAccessibleServerIds, getAccessibleServerIds,
getApplicationStats, getApplicationStats,
getContainerLogs, getContainerLogs,
getWebServerSettings,
IS_CLOUD, IS_CLOUD,
mechanizeDockerContainer, mechanizeDockerContainer,
readConfig, readConfig,
@@ -88,11 +87,7 @@ export const applicationRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create an application", message: "You need to use a server to create an application",

View File

@@ -91,11 +91,7 @@ export const composeRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a compose", message: "You need to use a server to create a compose",
@@ -589,11 +585,7 @@ export const composeRouter = createTRPCRouter({
await checkServiceAccess(ctx, environment.projectId, "create"); await checkServiceAccess(ctx, environment.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a compose", message: "You need to use a server to create a compose",

View File

@@ -8,7 +8,6 @@ import {
findProjectById, findProjectById,
getAccessibleServerIds, getAccessibleServerIds,
getContainerLogs, getContainerLogs,
getWebServerSettings,
IS_CLOUD, IS_CLOUD,
rebuildDatabase, rebuildDatabase,
removeLibsqlById, removeLibsqlById,
@@ -52,11 +51,7 @@ export const libsqlRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a Libsql", message: "You need to use a server to create a Libsql",

View File

@@ -12,7 +12,6 @@ import {
getAccessibleServerIds, getAccessibleServerIds,
getContainerLogs, getContainerLogs,
getServiceContainerCommand, getServiceContainerCommand,
getWebServerSettings,
IS_CLOUD, IS_CLOUD,
rebuildDatabase, rebuildDatabase,
removeMariadbById, removeMariadbById,
@@ -63,11 +62,7 @@ export const mariadbRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a Mariadb", message: "You need to use a server to create a Mariadb",

View File

@@ -12,7 +12,6 @@ import {
getAccessibleServerIds, getAccessibleServerIds,
getContainerLogs, getContainerLogs,
getServiceContainerCommand, getServiceContainerCommand,
getWebServerSettings,
IS_CLOUD, IS_CLOUD,
rebuildDatabase, rebuildDatabase,
removeMongoById, removeMongoById,
@@ -62,11 +61,7 @@ export const mongoRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a mongo", message: "You need to use a server to create a mongo",

View File

@@ -12,7 +12,6 @@ import {
getAccessibleServerIds, getAccessibleServerIds,
getContainerLogs, getContainerLogs,
getServiceContainerCommand, getServiceContainerCommand,
getWebServerSettings,
IS_CLOUD, IS_CLOUD,
rebuildDatabase, rebuildDatabase,
removeMySqlById, removeMySqlById,
@@ -63,11 +62,7 @@ export const mysqlRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a MySQL", message: "You need to use a server to create a MySQL",

View File

@@ -13,7 +13,6 @@ import {
getContainerLogs, getContainerLogs,
getMountPath, getMountPath,
getServiceContainerCommand, getServiceContainerCommand,
getWebServerSettings,
IS_CLOUD, IS_CLOUD,
rebuildDatabase, rebuildDatabase,
removePostgresById, removePostgresById,
@@ -64,11 +63,7 @@ export const postgresRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a Postgres", message: "You need to use a server to create a Postgres",

View File

@@ -8,7 +8,6 @@ import {
requestToHeaders, requestToHeaders,
} from "@dokploy/server/index"; } from "@dokploy/server/index";
import { auth } from "@dokploy/server/lib/auth"; import { auth } from "@dokploy/server/lib/auth";
import { getWebServerSettings } from "@dokploy/server/services/web-server-settings";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import { and, asc, eq } from "drizzle-orm"; import { and, asc, eq } from "drizzle-orm";
import { z } from "zod"; import { z } from "zod";
@@ -44,13 +43,6 @@ export const ssoRouter = createTRPCRouter({
owner.user.enableEnterpriseFeatures && owner.user.isValidEnterpriseLicense owner.user.enableEnterpriseFeatures && owner.user.isValidEnterpriseLicense
); );
}), }),
enforceSSO: publicProcedure.query(async () => {
if (IS_CLOUD) {
return false;
}
const settings = await getWebServerSettings();
return settings?.enforceSSO ?? false;
}),
listProviders: enterpriseProcedure.query(async ({ ctx }) => { listProviders: enterpriseProcedure.query(async ({ ctx }) => {
const providers = await db.query.ssoProvider.findMany({ const providers = await db.query.ssoProvider.findMany({
where: and( where: and(

View File

@@ -11,7 +11,6 @@ import {
getAccessibleServerIds, getAccessibleServerIds,
getContainerLogs, getContainerLogs,
getServiceContainerCommand, getServiceContainerCommand,
getWebServerSettings,
IS_CLOUD, IS_CLOUD,
rebuildDatabase, rebuildDatabase,
removeRedisById, removeRedisById,
@@ -60,11 +59,7 @@ export const redisRouter = createTRPCRouter({
await checkServiceAccess(ctx, project.projectId, "create"); await checkServiceAccess(ctx, project.projectId, "create");
const webServerSettings = await getWebServerSettings(); if (IS_CLOUD && !input.serverId) {
if (
(IS_CLOUD || webServerSettings?.remoteServersOnly) &&
!input.serverId
) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You need to use a server to create a Redis", message: "You need to use a server to create a Redis",

View File

@@ -75,12 +75,7 @@ export const scheduleRouter = createTRPCRouter({
} }
} }
} }
const newSchedule = await createSchedule({ const newSchedule = await createSchedule(input);
...input,
...(input.scheduleType === "dokploy-server" && {
organizationId: ctx.session.activeOrganizationId,
}),
});
if (newSchedule?.enabled) { if (newSchedule?.enabled) {
if (IS_CLOUD) { if (IS_CLOUD) {
@@ -167,6 +162,17 @@ export const scheduleRouter = createTRPCRouter({
}); });
} }
} }
if (
existingSchedule.scheduleType === "dokploy-server" &&
existingSchedule.userId &&
existingSchedule.userId !== ctx.user.id
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You can only manage your own host-level schedules.",
});
}
} }
const updatedSchedule = await updateSchedule(input); const updatedSchedule = await updateSchedule(input);
@@ -250,6 +256,17 @@ export const scheduleRouter = createTRPCRouter({
}); });
} }
} }
if (
scheduleItem.scheduleType === "dokploy-server" &&
scheduleItem.userId &&
scheduleItem.userId !== ctx.user.id
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You can only manage your own host-level schedules.",
});
}
} }
await deleteSchedule(input.scheduleId); await deleteSchedule(input.scheduleId);
@@ -306,27 +323,21 @@ export const scheduleRouter = createTRPCRouter({
} }
} }
if (input.scheduleType === "dokploy-server") { if (
const member = await findMemberByUserId( input.scheduleType === "dokploy-server" &&
ctx.user.id, input.id !== ctx.user.id
ctx.session.activeOrganizationId, ) {
); throw new TRPCError({
if (member.role !== "owner" && member.role !== "admin") { code: "UNAUTHORIZED",
throw new TRPCError({ message: "You can only list your own host-level schedules.",
code: "FORBIDDEN", });
message: "Only owners and admins can list host-level schedules.",
});
}
} }
} }
const where = { const where = {
application: eq(schedules.applicationId, input.id), application: eq(schedules.applicationId, input.id),
compose: eq(schedules.composeId, input.id), compose: eq(schedules.composeId, input.id),
server: eq(schedules.serverId, input.id), server: eq(schedules.serverId, input.id),
"dokploy-server": eq( "dokploy-server": eq(schedules.userId, input.id),
schedules.organizationId,
ctx.session.activeOrganizationId,
),
}; };
return db.query.schedules.findMany({ return db.query.schedules.findMany({
where: where[input.scheduleType], where: where[input.scheduleType],
@@ -365,6 +376,17 @@ export const scheduleRouter = createTRPCRouter({
}); });
} }
} }
if (
schedule.scheduleType === "dokploy-server" &&
schedule.userId &&
schedule.userId !== ctx.user.id
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this schedule.",
});
}
} }
return schedule; return schedule;
}), }),
@@ -417,6 +439,17 @@ export const scheduleRouter = createTRPCRouter({
}); });
} }
} }
if (
scheduleItem.scheduleType === "dokploy-server" &&
scheduleItem.userId &&
scheduleItem.userId !== ctx.user.id
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You can only manage your own host-level schedules.",
});
}
} }
try { try {
await runCommand(input.scheduleId); await runCommand(input.scheduleId);

View File

@@ -45,7 +45,7 @@ export const securityRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId); const security = await findSecurityById(input.securityId);
await checkServicePermissionAndAccess(ctx, security.applicationId, { await checkServicePermissionAndAccess(ctx, security.applicationId, {
service: ["create"], service: ["delete"],
}); });
const result = await deleteSecurityById(input.securityId); const result = await deleteSecurityById(input.securityId);
await audit(ctx, { await audit(ctx, {

View File

@@ -77,7 +77,6 @@ import { appRouter } from "../root";
import { import {
adminProcedure, adminProcedure,
createTRPCRouter, createTRPCRouter,
enterpriseProcedure,
protectedProcedure, protectedProcedure,
publicProcedure, publicProcedure,
} from "../trpc"; } from "../trpc";
@@ -446,50 +445,6 @@ export const settingsRouter = createTRPCRouter({
return true; return true;
}), }),
updateRemoteServersOnly: enterpriseProcedure
.input(z.object({ remoteServersOnly: z.boolean() }))
.mutation(async ({ input, ctx }) => {
if (IS_CLOUD) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "This feature is only available for self-hosted instances",
});
}
await updateWebServerSettings({
remoteServersOnly: input.remoteServersOnly,
});
await audit(ctx, {
action: "update",
resourceType: "settings",
resourceName: "remote-servers-only",
});
return true;
}),
updateEnforceSSO: enterpriseProcedure
.input(z.object({ enforceSSO: z.boolean() }))
.mutation(async ({ input, ctx }) => {
if (IS_CLOUD) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "This feature is only available for self-hosted instances",
});
}
await updateWebServerSettings({
enforceSSO: input.enforceSSO,
});
await audit(ctx, {
action: "update",
resourceType: "settings",
resourceName: "enforce-sso",
});
return true;
}),
readTraefikConfig: adminProcedure.query(() => { readTraefikConfig: adminProcedure.query(() => {
if (IS_CLOUD) { if (IS_CLOUD) {
return true; return true;

View File

@@ -3,11 +3,11 @@ import { boolean, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod"; import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { organization } from "./account";
import { applications } from "./application"; import { applications } from "./application";
import { compose } from "./compose"; import { compose } from "./compose";
import { deployments } from "./deployment"; import { deployments } from "./deployment";
import { server } from "./server"; import { server } from "./server";
import { user } from "./user";
import { generateAppName } from "./utils"; import { generateAppName } from "./utils";
export const shellTypes = pgEnum("shellType", ["bash", "sh"]); export const shellTypes = pgEnum("shellType", ["bash", "sh"]);
@@ -46,7 +46,7 @@ export const schedules = pgTable("schedule", {
serverId: text("serverId").references(() => server.serverId, { serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade", onDelete: "cascade",
}), }),
organizationId: text("organizationId").references(() => organization.id, { userId: text("userId").references(() => user.id, {
onDelete: "cascade", onDelete: "cascade",
}), }),
enabled: boolean("enabled").notNull().default(true), enabled: boolean("enabled").notNull().default(true),
@@ -71,9 +71,9 @@ export const schedulesRelations = relations(schedules, ({ one, many }) => ({
fields: [schedules.serverId], fields: [schedules.serverId],
references: [server.serverId], references: [server.serverId],
}), }),
organization: one(organization, { user: one(user, {
fields: [schedules.organizationId], fields: [schedules.userId],
references: [organization.id], references: [user.id],
}), }),
deployments: many(deployments), deployments: many(deployments),
})); }));

View File

@@ -96,10 +96,6 @@ export const webServerSettings = pgTable("webServerSettings", {
metaTitle: null, metaTitle: null,
footerText: null, footerText: null,
}), }),
// Deployment Configuration (self-hosted only)
remoteServersOnly: boolean("remoteServersOnly").notNull().default(false),
// Auth Configuration (self-hosted only)
enforceSSO: boolean("enforceSSO").notNull().default(false),
// Cache Cleanup Configuration // Cache Cleanup Configuration
cleanupCacheApplications: boolean("cleanupCacheApplications") cleanupCacheApplications: boolean("cleanupCacheApplications")
.notNull() .notNull()
@@ -159,8 +155,6 @@ export const apiUpdateWebServerSettings = createSchema.partial().extend({
cleanupCacheApplications: z.boolean().optional(), cleanupCacheApplications: z.boolean().optional(),
cleanupCacheOnPreviews: z.boolean().optional(), cleanupCacheOnPreviews: z.boolean().optional(),
cleanupCacheOnCompose: z.boolean().optional(), cleanupCacheOnCompose: z.boolean().optional(),
remoteServersOnly: z.boolean().optional(),
enforceSSO: z.boolean().optional(),
}); });
export const apiAssignDomain = z export const apiAssignDomain = z

View File

@@ -100,7 +100,6 @@ export * from "./utils/docker/types";
export * from "./utils/docker/utils"; export * from "./utils/docker/utils";
export * from "./utils/filesystem/directory"; export * from "./utils/filesystem/directory";
export * from "./utils/filesystem/ssh"; export * from "./utils/filesystem/ssh";
export * from "./utils/git-branch-validation";
export * from "./utils/gpu-setup"; export * from "./utils/gpu-setup";
export * from "./utils/notifications/build-error"; export * from "./utils/notifications/build-error";
export * from "./utils/notifications/build-success"; export * from "./utils/notifications/build-success";
@@ -109,6 +108,7 @@ export * from "./utils/notifications/docker-cleanup";
export * from "./utils/notifications/dokploy-restart"; export * from "./utils/notifications/dokploy-restart";
export * from "./utils/notifications/server-threshold"; export * from "./utils/notifications/server-threshold";
export * from "./utils/notifications/utils"; export * from "./utils/notifications/utils";
export * from "./utils/git-branch-validation";
export * from "./utils/process/execAsync"; export * from "./utils/process/execAsync";
export * from "./utils/process/spawnAsync"; export * from "./utils/process/spawnAsync";
export * from "./utils/providers/bitbucket"; export * from "./utils/providers/bitbucket";

View File

@@ -80,10 +80,9 @@ export const checkPermission = async (
const { id: userId } = ctx.user; const { id: userId } = ctx.user;
const { activeOrganizationId: organizationId } = ctx.session; const { activeOrganizationId: organizationId } = ctx.session;
const memberRecord = await findMemberByUserId(userId, organizationId); const memberRecord = await findMemberByUserId(userId, organizationId);
const isStaticRole = memberRecord.role in staticRoles;
const isPrivilegedStaticRole = if (isStaticRole) {
memberRecord.role === "owner" || memberRecord.role === "admin";
if (isPrivilegedStaticRole) {
const allEnterprise = Object.keys(permissions).every((r) => const allEnterprise = Object.keys(permissions).every((r) =>
enterpriseOnlyResources.has(r), enterpriseOnlyResources.has(r),
); );
@@ -165,8 +164,6 @@ const getLegacyOverrides = (
}, },
sshKeys: { sshKeys: {
read: !!memberRecord.canAccessToSSHKeys, read: !!memberRecord.canAccessToSSHKeys,
create: !!memberRecord.canAccessToSSHKeys,
delete: !!memberRecord.canAccessToSSHKeys,
}, },
gitProviders: { gitProviders: {
read: !!memberRecord.canAccessToGitProviders, read: !!memberRecord.canAccessToGitProviders,

View File

@@ -85,9 +85,6 @@ export const findScheduleOrganizationId = async (scheduleId: string) => {
if (schedule?.server) { if (schedule?.server) {
return schedule?.server?.organization?.id; return schedule?.server?.organization?.id;
} }
if (schedule?.organizationId) {
return schedule.organizationId;
}
return null; return null;
}; };

View File

@@ -54,7 +54,7 @@ Compose Type: ${composeType} ✅`;
cd "${projectPath}"; cd "${projectPath}";
${compose.isolatedDeployment ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create ${compose.composeType === "stack" ? "--driver overlay" : ""} --attachable ${compose.appName}` : ""} ${compose.isolatedDeployment ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create ${compose.composeType === "stack" ? "--driver overlay" : ""} --attachable ${compose.appName}` : ""}
env -i PATH="$PATH" HOME="$HOME" ${exportEnvCommand} docker ${command.split(" ").join(" ")} 2>&1 || { echo "Error: ❌ Docker command failed"; exit 1; } env -i PATH="$PATH" ${exportEnvCommand} docker ${command.split(" ").join(" ")} 2>&1 || { echo "Error: ❌ Docker command failed"; exit 1; }
${compose.isolatedDeployment ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""} ${compose.isolatedDeployment ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""}
echo "Docker Compose Deployed: ✅"; echo "Docker Compose Deployed: ✅";

View File

@@ -11,7 +11,7 @@ export const initSchedules = async () => {
server: true, server: true,
application: true, application: true,
compose: true, compose: true,
organization: true, user: true,
}, },
}); });

219
pnpm-lock.yaml generated
View File

@@ -51,7 +51,7 @@ importers:
version: 4.12.2 version: 4.12.2
inngest: inngest:
specifier: 3.40.1 specifier: 3.40.1
version: 3.40.1(encoding@0.1.13)(h3@1.15.1)(hono@4.12.2)(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(typescript@5.9.3) version: 3.40.1(encoding@0.1.13)(h3@1.15.1)(hono@4.12.2)(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(typescript@5.9.3)
pino: pino:
specifier: 9.4.0 specifier: 9.4.0
version: 9.4.0 version: 9.4.0
@@ -115,10 +115,10 @@ importers:
version: 2.0.30(zod@4.3.6) version: 2.0.30(zod@4.3.6)
'@better-auth/api-key': '@better-auth/api-key':
specifier: 1.5.4 specifier: 1.5.4
version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(4c76b7da14d170b1922a58fb44839507)) version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(71a760b327c31dd12606432855d01199))
'@better-auth/sso': '@better-auth/sso':
specifier: 1.5.4 specifier: 1.5.4
version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(4c76b7da14d170b1922a58fb44839507))(better-call@2.0.2(zod@4.3.6)) version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(71a760b327c31dd12606432855d01199))(better-call@2.0.2(zod@4.3.6))
'@codemirror/autocomplete': '@codemirror/autocomplete':
specifier: ^6.18.6 specifier: ^6.18.6
version: 6.20.0 version: 6.20.0
@@ -244,7 +244,7 @@ importers:
version: 11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3) version: 11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3)
'@trpc/next': '@trpc/next':
specifier: ^11.10.0 specifier: ^11.10.0
version: 11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(react@18.2.0)(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) version: 11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(react@18.2.0)(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)
'@trpc/react-query': '@trpc/react-query':
specifier: ^11.10.0 specifier: ^11.10.0
version: 11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(react@18.2.0)(typescript@5.9.3) version: 11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(react@18.2.0)(typescript@5.9.3)
@@ -280,7 +280,7 @@ importers:
version: 5.1.1(encoding@0.1.13) version: 5.1.1(encoding@0.1.13)
better-auth: better-auth:
specifier: 1.5.4 specifier: 1.5.4
version: 1.5.4(4c76b7da14d170b1922a58fb44839507) version: 1.5.4(71a760b327c31dd12606432855d01199)
bl: bl:
specifier: 6.0.11 specifier: 6.0.11
version: 6.0.11 version: 6.0.11
@@ -342,14 +342,14 @@ importers:
specifier: 3.3.11 specifier: 3.3.11
version: 3.3.11 version: 3.3.11
next: next:
specifier: 16.2.6 specifier: ^16.2.0
version: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
next-themes: next-themes:
specifier: ^0.2.1 specifier: ^0.2.1
version: 0.2.1(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 0.2.1(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
nextjs-toploader: nextjs-toploader:
specifier: ^3.9.17 specifier: ^3.9.17
version: 3.9.17(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 3.9.17(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
node-os-utils: node-os-utils:
specifier: 2.0.1 specifier: 2.0.1
version: 2.0.1 version: 2.0.1
@@ -630,10 +630,10 @@ importers:
version: 2.0.30(zod@4.3.6) version: 2.0.30(zod@4.3.6)
'@better-auth/api-key': '@better-auth/api-key':
specifier: 1.5.4 specifier: 1.5.4
version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(9312701f7238452a4ac943b2bb39c424)) version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9))
'@better-auth/sso': '@better-auth/sso':
specifier: 1.5.4 specifier: 1.5.4
version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(9312701f7238452a4ac943b2bb39c424))(better-call@2.0.2(zod@4.3.6)) version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9))(better-call@2.0.2(zod@4.3.6))
'@better-auth/utils': '@better-auth/utils':
specifier: 0.3.1 specifier: 0.3.1
version: 0.3.1 version: 0.3.1
@@ -672,7 +672,7 @@ importers:
version: 5.1.1(encoding@0.1.13) version: 5.1.1(encoding@0.1.13)
better-auth: better-auth:
specifier: 1.5.4 specifier: 1.5.4
version: 1.5.4(9312701f7238452a4ac943b2bb39c424) version: 1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9)
better-call: better-call:
specifier: 2.0.2 specifier: 2.0.2
version: 2.0.2(zod@4.3.6) version: 2.0.2(zod@4.3.6)
@@ -775,7 +775,7 @@ importers:
devDependencies: devDependencies:
'@better-auth/cli': '@better-auth/cli':
specifier: 1.4.21 specifier: 1.4.21
version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0(socks@2.8.8))(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)) version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0(socks@2.8.8))(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1))
'@types/adm-zip': '@types/adm-zip':
specifier: ^0.5.7 specifier: ^0.5.7
version: 0.5.7 version: 0.5.7
@@ -1878,53 +1878,53 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@next/env@16.2.6': '@next/env@16.2.0':
resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} resolution: {integrity: sha512-OZIbODWWAi0epQRCRjNe1VO45LOFBzgiyqmTLzIqWq6u1wrxKnAyz1HH6tgY/Mc81YzIjRPoYsPAEr4QV4l9TA==}
'@next/swc-darwin-arm64@16.2.6': '@next/swc-darwin-arm64@16.2.0':
resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==} resolution: {integrity: sha512-/JZsqKzKt01IFoiLLAzlNqys7qk2F3JkcUhj50zuRhKDQkZNOz9E5N6wAQWprXdsvjRP4lTFj+/+36NSv5AwhQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@next/swc-darwin-x64@16.2.6': '@next/swc-darwin-x64@16.2.0':
resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==} resolution: {integrity: sha512-/hV8erWq4SNlVgglUiW5UmQ5Hwy5EW/AbbXlJCn6zkfKxTy/E/U3V8U1Ocm2YCTUoFgQdoMxRyRMOW5jYy4ygg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@next/swc-linux-arm64-gnu@16.2.6': '@next/swc-linux-arm64-gnu@16.2.0':
resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==} resolution: {integrity: sha512-GkjL/Q7MWOwqWR9zoxu1TIHzkOI2l2BHCf7FzeQG87zPgs+6WDh+oC9Sw9ARuuL/FUk6JNCgKRkA6rEQYadUaw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-arm64-musl@16.2.6': '@next/swc-linux-arm64-musl@16.2.0':
resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==} resolution: {integrity: sha512-1ffhC6KY5qWLg5miMlKJp3dZbXelEfjuXt1qcp5WzSCQy36CV3y+JT7OC1WSFKizGQCDOcQbfkH/IjZP3cdRNA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-x64-gnu@16.2.6': '@next/swc-linux-x64-gnu@16.2.0':
resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==} resolution: {integrity: sha512-FmbDcZQ8yJRq93EJSL6xaE0KK/Rslraf8fj1uViGxg7K4CKBCRYSubILJPEhjSgZurpcPQq12QNOJQ0DRJl6Hg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-linux-x64-musl@16.2.6': '@next/swc-linux-x64-musl@16.2.0':
resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==} resolution: {integrity: sha512-HzjIHVkmGAwRbh/vzvoBWWEbb8BBZPxBvVbDQDvzHSf3D8RP/4vjw7MNLDXFF9Q1WEzeQyEj2zdxBtVAHu5Oyw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-win32-arm64-msvc@16.2.6': '@next/swc-win32-arm64-msvc@16.2.0':
resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==} resolution: {integrity: sha512-UMiFNQf5H7+1ZsZPxEsA064WEuFbRNq/kEXyepbCnSErp4f5iut75dBA8UeerFIG3vDaQNOfCpevnERPp2V+nA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@next/swc-win32-x64-msvc@16.2.6': '@next/swc-win32-x64-msvc@16.2.0':
resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==} resolution: {integrity: sha512-DRrNJKW+/eimrZgdhVN1uvkN1OI4j6Lpefwr44jKQ0YQzztlmOBUUzHuV5GxOMPK3nmodAYElUVCY8ZXo/IWeA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -4171,7 +4171,6 @@ packages:
'@ungap/structured-clone@1.3.0': '@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
deprecated: Potential CWE-502 - Update to 1.3.1 or higher
'@vercel/oidc@3.1.0': '@vercel/oidc@3.1.0':
resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==}
@@ -6566,8 +6565,8 @@ packages:
react: '*' react: '*'
react-dom: '*' react-dom: '*'
next@16.2.6: next@16.2.0:
resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} resolution: {integrity: sha512-NLBVrJy1pbV1Yn00L5sU4vFyAHt5XuSjzrNyFnxo6Com0M0KrL6hHM5B99dbqXb2bE9pm4Ow3Zl1xp6HVY9edQ==}
engines: {node: '>=20.9.0'} engines: {node: '>=20.9.0'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -8665,21 +8664,21 @@ snapshots:
'@balena/dockerignore@1.0.2': {} '@balena/dockerignore@1.0.2': {}
'@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(4c76b7da14d170b1922a58fb44839507))': '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9))':
dependencies: dependencies:
'@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)
'@better-auth/utils': 0.3.1 '@better-auth/utils': 0.3.1
better-auth: 1.5.4(4c76b7da14d170b1922a58fb44839507) better-auth: 1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9)
zod: 4.3.6 zod: 4.3.6
'@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(9312701f7238452a4ac943b2bb39c424))': '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(71a760b327c31dd12606432855d01199))':
dependencies: dependencies:
'@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)
'@better-auth/utils': 0.3.1 '@better-auth/utils': 0.3.1
better-auth: 1.5.4(9312701f7238452a4ac943b2bb39c424) better-auth: 1.5.4(71a760b327c31dd12606432855d01199)
zod: 4.3.6 zod: 4.3.6
'@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0(socks@2.8.8))(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1))': '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0(socks@2.8.8))(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1))':
dependencies: dependencies:
'@babel/core': 7.29.0 '@babel/core': 7.29.0
'@babel/preset-react': 7.28.5(@babel/core@7.29.0) '@babel/preset-react': 7.28.5(@babel/core@7.29.0)
@@ -8691,7 +8690,7 @@ snapshots:
'@mrleebo/prisma-ast': 0.13.1 '@mrleebo/prisma-ast': 0.13.1
'@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) '@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
'@types/pg': 8.16.0 '@types/pg': 8.16.0
better-auth: 1.4.21(23a7835d44d42e8df1218333453e2b24) better-auth: 1.4.21(97e31320bc7dc8a33b04861de973b388)
better-sqlite3: 12.6.2 better-sqlite3: 12.6.2
c12: 3.3.3 c12: 3.3.3
chalk: 5.6.2 chalk: 5.6.2
@@ -8825,24 +8824,24 @@ snapshots:
'@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) '@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)
'@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(4c76b7da14d170b1922a58fb44839507))(better-call@2.0.2(zod@4.3.6))': '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9))(better-call@2.0.2(zod@4.3.6))':
dependencies: dependencies:
'@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)
'@better-auth/utils': 0.3.1 '@better-auth/utils': 0.3.1
'@better-fetch/fetch': 1.1.21 '@better-fetch/fetch': 1.1.21
better-auth: 1.5.4(4c76b7da14d170b1922a58fb44839507) better-auth: 1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9)
better-call: 2.0.2(zod@4.3.6) better-call: 2.0.2(zod@4.3.6)
fast-xml-parser: 5.5.1 fast-xml-parser: 5.5.1
jose: 6.1.3 jose: 6.1.3
samlify: 2.10.2 samlify: 2.10.2
zod: 4.3.6 zod: 4.3.6
'@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(9312701f7238452a4ac943b2bb39c424))(better-call@2.0.2(zod@4.3.6))': '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(71a760b327c31dd12606432855d01199))(better-call@2.0.2(zod@4.3.6))':
dependencies: dependencies:
'@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)
'@better-auth/utils': 0.3.1 '@better-auth/utils': 0.3.1
'@better-fetch/fetch': 1.1.21 '@better-fetch/fetch': 1.1.21
better-auth: 1.5.4(9312701f7238452a4ac943b2bb39c424) better-auth: 1.5.4(71a760b327c31dd12606432855d01199)
better-call: 2.0.2(zod@4.3.6) better-call: 2.0.2(zod@4.3.6)
fast-xml-parser: 5.5.1 fast-xml-parser: 5.5.1
jose: 6.1.3 jose: 6.1.3
@@ -9513,30 +9512,30 @@ snapshots:
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
optional: true optional: true
'@next/env@16.2.6': {} '@next/env@16.2.0': {}
'@next/swc-darwin-arm64@16.2.6': '@next/swc-darwin-arm64@16.2.0':
optional: true optional: true
'@next/swc-darwin-x64@16.2.6': '@next/swc-darwin-x64@16.2.0':
optional: true optional: true
'@next/swc-linux-arm64-gnu@16.2.6': '@next/swc-linux-arm64-gnu@16.2.0':
optional: true optional: true
'@next/swc-linux-arm64-musl@16.2.6': '@next/swc-linux-arm64-musl@16.2.0':
optional: true optional: true
'@next/swc-linux-x64-gnu@16.2.6': '@next/swc-linux-x64-gnu@16.2.0':
optional: true optional: true
'@next/swc-linux-x64-musl@16.2.6': '@next/swc-linux-x64-musl@16.2.0':
optional: true optional: true
'@next/swc-win32-arm64-msvc@16.2.6': '@next/swc-win32-arm64-msvc@16.2.0':
optional: true optional: true
'@next/swc-win32-x64-msvc@16.2.6': '@next/swc-win32-x64-msvc@16.2.0':
optional: true optional: true
'@noble/ciphers@2.1.1': {} '@noble/ciphers@2.1.1': {}
@@ -12027,11 +12026,11 @@ snapshots:
'@trpc/server': 11.10.0(typescript@5.9.3) '@trpc/server': 11.10.0(typescript@5.9.3)
typescript: 5.9.3 typescript: 5.9.3
'@trpc/next@11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(react@18.2.0)(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)': '@trpc/next@11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@18.2.0))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(react@18.2.0)(typescript@5.9.3))(@trpc/server@11.10.0(typescript@5.9.3))(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)':
dependencies: dependencies:
'@trpc/client': 11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3) '@trpc/client': 11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3)
'@trpc/server': 11.10.0(typescript@5.9.3) '@trpc/server': 11.10.0(typescript@5.9.3)
next: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
typescript: 5.9.3 typescript: 5.9.3
@@ -12535,7 +12534,7 @@ snapshots:
before-after-hook@2.2.3: {} before-after-hook@2.2.3: {}
better-auth@1.4.21(23a7835d44d42e8df1218333453e2b24): better-auth@1.4.21(97e31320bc7dc8a33b04861de973b388):
dependencies: dependencies:
'@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0) '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)
'@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)) '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))
@@ -12556,14 +12555,14 @@ snapshots:
drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
mongodb: 7.1.0(socks@2.8.8) mongodb: 7.1.0(socks@2.8.8)
mysql2: 3.15.3 mysql2: 3.15.3
next: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
pg: 8.18.0 pg: 8.18.0
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)
better-auth@1.5.4(4c76b7da14d170b1922a58fb44839507): better-auth@1.5.4(48b68ecaf84f5e14652b8d87fbbd7ca9):
dependencies: dependencies:
'@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)
'@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))) '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))
@@ -12589,7 +12588,42 @@ snapshots:
drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
mongodb: 7.1.0(socks@2.8.8) mongodb: 7.1.0(socks@2.8.8)
mysql2: 3.15.3 mysql2: 3.15.3
next: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
pg: 8.18.0
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)
transitivePeerDependencies:
- '@cloudflare/workers-types'
better-auth@1.5.4(71a760b327c31dd12606432855d01199):
dependencies:
'@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)
'@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))
'@better-auth/kysely-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11)
'@better-auth/memory-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)
'@better-auth/mongo-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0(socks@2.8.8))
'@better-auth/prisma-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
'@better-auth/telemetry': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))
'@better-auth/utils': 0.3.1
'@better-fetch/fetch': 1.1.21
'@noble/ciphers': 2.1.1
'@noble/hashes': 2.0.1
better-call: 1.3.2(zod@4.3.6)
defu: 6.1.4
jose: 6.1.3
kysely: 0.28.11
nanostores: 1.1.1
zod: 4.3.6
optionalDependencies:
'@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
better-sqlite3: 12.6.2
drizzle-kit: 0.31.9
drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
mongodb: 7.1.0(socks@2.8.8)
mysql2: 3.15.3
next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
pg: 8.18.0 pg: 8.18.0
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)
react: 18.2.0 react: 18.2.0
@@ -12598,41 +12632,6 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@cloudflare/workers-types' - '@cloudflare/workers-types'
better-auth@1.5.4(9312701f7238452a4ac943b2bb39c424):
dependencies:
'@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)
'@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))
'@better-auth/kysely-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11)
'@better-auth/memory-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)
'@better-auth/mongo-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0(socks@2.8.8))
'@better-auth/prisma-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
'@better-auth/telemetry': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))
'@better-auth/utils': 0.3.1
'@better-fetch/fetch': 1.1.21
'@noble/ciphers': 2.1.1
'@noble/hashes': 2.0.1
better-call: 1.3.2(zod@4.3.6)
defu: 6.1.4
jose: 6.1.3
kysely: 0.28.11
nanostores: 1.1.1
zod: 4.3.6
optionalDependencies:
'@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
better-sqlite3: 12.6.2
drizzle-kit: 0.31.9
drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))
mongodb: 7.1.0(socks@2.8.8)
mysql2: 3.15.3
next: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
pg: 8.18.0
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)
transitivePeerDependencies:
- '@cloudflare/workers-types'
better-call@1.1.8(zod@4.3.6): better-call@1.1.8(zod@4.3.6):
dependencies: dependencies:
'@better-auth/utils': 0.3.1 '@better-auth/utils': 0.3.1
@@ -13882,7 +13881,7 @@ snapshots:
inline-style-parser@0.2.7: {} inline-style-parser@0.2.7: {}
inngest@3.40.1(encoding@0.1.13)(h3@1.15.1)(hono@4.12.2)(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(typescript@5.9.3): inngest@3.40.1(encoding@0.1.13)(h3@1.15.1)(hono@4.12.2)(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(typescript@5.9.3):
dependencies: dependencies:
'@bufbuild/protobuf': 2.11.0 '@bufbuild/protobuf': 2.11.0
'@inngest/ai': 0.1.7 '@inngest/ai': 0.1.7
@@ -13909,7 +13908,7 @@ snapshots:
optionalDependencies: optionalDependencies:
h3: 1.15.1 h3: 1.15.1
hono: 4.12.2 hono: 4.12.2
next: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
@@ -14705,15 +14704,15 @@ snapshots:
neotraverse@0.6.18: {} neotraverse@0.6.18: {}
next-themes@0.2.1(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): next-themes@0.2.1(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies: dependencies:
next: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
next@16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies: dependencies:
'@next/env': 16.2.6 '@next/env': 16.2.0
'@swc/helpers': 0.5.15 '@swc/helpers': 0.5.15
baseline-browser-mapping: 2.10.0 baseline-browser-mapping: 2.10.0
caniuse-lite: 1.0.30001774 caniuse-lite: 1.0.30001774
@@ -14722,23 +14721,23 @@ snapshots:
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
styled-jsx: 5.1.6(@babel/core@7.29.0)(react@18.2.0) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@18.2.0)
optionalDependencies: optionalDependencies:
'@next/swc-darwin-arm64': 16.2.6 '@next/swc-darwin-arm64': 16.2.0
'@next/swc-darwin-x64': 16.2.6 '@next/swc-darwin-x64': 16.2.0
'@next/swc-linux-arm64-gnu': 16.2.6 '@next/swc-linux-arm64-gnu': 16.2.0
'@next/swc-linux-arm64-musl': 16.2.6 '@next/swc-linux-arm64-musl': 16.2.0
'@next/swc-linux-x64-gnu': 16.2.6 '@next/swc-linux-x64-gnu': 16.2.0
'@next/swc-linux-x64-musl': 16.2.6 '@next/swc-linux-x64-musl': 16.2.0
'@next/swc-win32-arm64-msvc': 16.2.6 '@next/swc-win32-arm64-msvc': 16.2.0
'@next/swc-win32-x64-msvc': 16.2.6 '@next/swc-win32-x64-msvc': 16.2.0
'@opentelemetry/api': 1.9.0 '@opentelemetry/api': 1.9.0
sharp: 0.34.5 sharp: 0.34.5
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'
- babel-plugin-macros - babel-plugin-macros
nextjs-toploader@3.9.17(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): nextjs-toploader@3.9.17(next@16.2.0(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies: dependencies:
next: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
nprogress: 0.2.0 nprogress: 0.2.0
prop-types: 15.8.1 prop-types: 15.8.1
react: 18.2.0 react: 18.2.0