mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-10-15 21:31:11 +00:00
Merge branch 'canary' into feat/log-management
This commit is contained in:
@@ -14,34 +14,34 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get version from package.json
|
||||
run: echo "VERSION=$(jq -r .version ./apps/dokploy/package.json)" >> $GITHUB_ENV
|
||||
run: echo "VERSION=$(jq -r .version ./apps/dokploy/package.json)" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Get latest GitHub tag
|
||||
run: |
|
||||
LATEST_TAG=$(git ls-remote --tags origin | awk -F'/' '{print $3}' | sort -V | tail -n1)
|
||||
echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
|
||||
echo $LATEST_TAG
|
||||
echo "LATEST_TAG=$LATEST_TAG" >> "$GITHUB_ENV"
|
||||
echo "$LATEST_TAG"
|
||||
- name: Compare versions
|
||||
run: |
|
||||
if [ "${{ env.VERSION }}" != "${{ env.LATEST_TAG }}" ]; then
|
||||
if [ "$VERSION" != "$LATEST_TAG" ]; then
|
||||
VERSION_CHANGED="true"
|
||||
else
|
||||
VERSION_CHANGED="false"
|
||||
fi
|
||||
echo "VERSION_CHANGED=$VERSION_CHANGED" >> $GITHUB_ENV
|
||||
echo "VERSION_CHANGED=$VERSION_CHANGED" >> "$GITHUB_ENV"
|
||||
echo "Comparing versions:"
|
||||
echo "Current version: ${{ env.VERSION }}"
|
||||
echo "Latest tag: ${{ env.LATEST_TAG }}"
|
||||
echo "Current version: $VERSION"
|
||||
echo "Latest tag: $LATEST_TAG"
|
||||
echo "Version changed: $VERSION_CHANGED"
|
||||
- name: Check if a PR already exists
|
||||
run: |
|
||||
PR_EXISTS=$(gh pr list --state open --base main --head canary --json number --jq '. | length')
|
||||
echo "PR_EXISTS=$PR_EXISTS" >> $GITHUB_ENV
|
||||
echo "PR_EXISTS=$PR_EXISTS" >> "$GITHUB_ENV"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
|
||||
@@ -56,12 +56,12 @@ jobs:
|
||||
git push origin canary
|
||||
|
||||
gh pr create \
|
||||
--title "🚀 Release ${{ env.VERSION }}" \
|
||||
--body '
|
||||
This PR promotes changes from `canary` to `main` for version ${{ env.VERSION }}.
|
||||
--title "🚀 Release $VERSION" \
|
||||
--body "
|
||||
This PR promotes changes from \`canary\` to \`main\` for version $VERSION.
|
||||
|
||||
### 🔍 Changes Include:
|
||||
- Version bump to ${{ env.VERSION }}
|
||||
- Version bump to $VERSION
|
||||
- All changes from canary branch
|
||||
|
||||
### ✅ Pre-merge Checklist:
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
- [ ] Documentation updated
|
||||
- [ ] Docker images built and tested
|
||||
|
||||
> 🤖 This PR was automatically generated by [GitHub Actions](https://github.com/actions)' \
|
||||
> 🤖 This PR was automatically generated by [GitHub Actions](https://github.com/actions)" \
|
||||
--base main \
|
||||
--head canary \
|
||||
--label "release" --label "automated pr" || true \
|
||||
|
||||
@@ -5,33 +5,38 @@ on:
|
||||
branches: [main, canary]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-and-push-cloud-image:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set tag and version
|
||||
id: meta-cloud
|
||||
run: |
|
||||
VERSION=$(jq -r .version apps/dokploy/package.json)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
echo "tags=siumauricio/cloud:latest,siumauricio/cloud:${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
echo "tags=siumauricio/cloud:latest,siumauricio/cloud:${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "tags=siumauricio/cloud:canary" >> $GITHUB_OUTPUT
|
||||
echo "tags=siumauricio/cloud:canary" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.cloud
|
||||
@@ -48,26 +53,28 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set tag and version
|
||||
id: meta-schedule
|
||||
run: |
|
||||
VERSION=$(jq -r .version apps/dokploy/package.json)
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
echo "tags=siumauricio/schedule:latest,siumauricio/schedule:${VERSION}" >> $GITHUB_OUTPUT
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
echo "tags=siumauricio/schedule:latest,siumauricio/schedule:${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "tags=siumauricio/schedule:canary" >> $GITHUB_OUTPUT
|
||||
echo "tags=siumauricio/schedule:canary" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.schedule
|
||||
@@ -80,26 +87,28 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set tag and version
|
||||
id: meta-server
|
||||
run: |
|
||||
VERSION=$(jq -r .version apps/dokploy/package.json)
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
echo "tags=siumauricio/server:latest,siumauricio/server:${VERSION}" >> $GITHUB_OUTPUT
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
echo "tags=siumauricio/server:latest,siumauricio/server:${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "tags=siumauricio/server:canary" >> $GITHUB_OUTPUT
|
||||
echo "tags=siumauricio/server:canary" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.server
|
||||
|
||||
@@ -8,18 +8,23 @@ on:
|
||||
env:
|
||||
IMAGE_NAME: dokploy/dokploy
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docker-amd:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -27,15 +32,15 @@ jobs:
|
||||
- name: Set tag and version
|
||||
id: meta
|
||||
run: |
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
VERSION=$(node -p "require('./apps/dokploy/package.json').version")
|
||||
elif [ "${{ github.ref }}" = "refs/heads/canary" ]; then
|
||||
elif [ "$GITHUB_REF" = "refs/heads/canary" ]; then
|
||||
TAG="canary"
|
||||
else
|
||||
TAG="feature"
|
||||
fi
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-amd64" >> $GITHUB_OUTPUT
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-amd64" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Prepare env file
|
||||
run: |
|
||||
@@ -43,7 +48,7 @@ jobs:
|
||||
cp apps/dokploy/.env.production.example apps/dokploy/.env.production
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
@@ -53,13 +58,15 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -68,15 +75,15 @@ jobs:
|
||||
id: meta
|
||||
run: |
|
||||
VERSION=$(node -p "require('./apps/dokploy/package.json').version")
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
VERSION=$(node -p "require('./apps/dokploy/package.json').version")
|
||||
elif [ "${{ github.ref }}" = "refs/heads/canary" ]; then
|
||||
elif [ "$GITHUB_REF" = "refs/heads/canary" ]; then
|
||||
TAG="canary"
|
||||
else
|
||||
TAG="feature"
|
||||
fi
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-arm64" >> $GITHUB_OUTPUT
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-arm64" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Prepare env file
|
||||
run: |
|
||||
@@ -84,7 +91,7 @@ jobs:
|
||||
cp apps/dokploy/.env.production.example apps/dokploy/.env.production
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64
|
||||
@@ -96,20 +103,22 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Create and push manifests
|
||||
run: |
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
VERSION=$(node -p "require('./apps/dokploy/package.json').version")
|
||||
TAG="latest"
|
||||
|
||||
@@ -121,7 +130,7 @@ jobs:
|
||||
${IMAGE_NAME}:${TAG}-amd64 \
|
||||
${IMAGE_NAME}:${TAG}-arm64
|
||||
|
||||
elif [ "${{ github.ref }}" = "refs/heads/canary" ]; then
|
||||
elif [ "$GITHUB_REF" = "refs/heads/canary" ]; then
|
||||
TAG="canary"
|
||||
docker buildx imagetools create -t ${IMAGE_NAME}:${TAG} \
|
||||
${IMAGE_NAME}:${TAG}-amd64 \
|
||||
@@ -138,32 +147,37 @@ jobs:
|
||||
needs: [combine-manifests]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
version: ${{ steps.get_version.outputs.version }}
|
||||
npm_version: ${{ steps.get_version.outputs.npm_version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=$(node -p "require('./apps/dokploy/package.json').version")
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "npm_version=${VERSION#v}" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "npm_version=${VERSION#v}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Fetch install.sh
|
||||
env:
|
||||
RELEASE_VERSION: ${{ steps.get_version.outputs.version }}
|
||||
run: |
|
||||
curl -fsSL https://raw.githubusercontent.com/Dokploy/website/main/apps/website/public/install.sh -o install.sh
|
||||
head -1 install.sh | grep -q '^#!' || { echo "Downloaded install.sh is not a shell script"; exit 1; }
|
||||
grep -q 'DOKPLOY_VERSION' install.sh || { echo "install.sh no longer supports DOKPLOY_VERSION pinning"; exit 1; }
|
||||
{ head -1 install.sh; echo "DOKPLOY_VERSION=\"\${DOKPLOY_VERSION:-${{ steps.get_version.outputs.version }}}\""; tail -n +2 install.sh; } > install-pinned.sh
|
||||
{ head -1 install.sh; echo "DOKPLOY_VERSION=\"\${DOKPLOY_VERSION:-${RELEASE_VERSION}}\""; tail -n +2 install.sh; } > install-pinned.sh
|
||||
mv install-pinned.sh install.sh
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: ${{ steps.get_version.outputs.version }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
@@ -179,15 +193,19 @@ jobs:
|
||||
needs: [generate-release]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NPM_VERSION: ${{ needs.generate-release.outputs.npm_version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.22.0
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 24.4.0
|
||||
cache: pnpm
|
||||
@@ -202,63 +220,63 @@ jobs:
|
||||
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/mcp.git /tmp/mcp-repo
|
||||
cd /tmp/mcp-repo
|
||||
|
||||
jq --arg v "${{ needs.generate-release.outputs.npm_version }}" '.version = $v' package.json > package.json.tmp
|
||||
jq --arg v "$NPM_VERSION" '.version = $v' package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
|
||||
cp ${{ github.workspace }}/openapi.json src/generated/openapi.json
|
||||
cp $GITHUB_WORKSPACE/openapi.json src/generated/openapi.json
|
||||
pnpm install
|
||||
pnpm run generate
|
||||
|
||||
git config user.name "Dokploy Bot"
|
||||
git config user.email "bot@dokploy.com"
|
||||
git add -A
|
||||
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.npm_version }}" \
|
||||
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
|
||||
git commit -m "chore: bump version to $NPM_VERSION" \
|
||||
-m "Source: $GITHUB_REPOSITORY@$GITHUB_SHA" \
|
||||
--allow-empty
|
||||
git push
|
||||
|
||||
echo "✅ MCP repo synced to version ${{ needs.generate-release.outputs.npm_version }}"
|
||||
echo "✅ MCP repo synced to version $NPM_VERSION"
|
||||
|
||||
- name: Sync version to CLI repository
|
||||
run: |
|
||||
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/cli.git /tmp/cli-repo
|
||||
cd /tmp/cli-repo
|
||||
|
||||
jq --arg v "${{ needs.generate-release.outputs.npm_version }}" '.version = $v' package.json > package.json.tmp
|
||||
jq --arg v "$NPM_VERSION" '.version = $v' package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
|
||||
cp ${{ github.workspace }}/openapi.json ./openapi.json
|
||||
cp $GITHUB_WORKSPACE/openapi.json ./openapi.json
|
||||
pnpm install
|
||||
pnpm run generate
|
||||
|
||||
git config user.name "Dokploy Bot"
|
||||
git config user.email "bot@dokploy.com"
|
||||
git add -A
|
||||
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.npm_version }}" \
|
||||
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
|
||||
git commit -m "chore: bump version to $NPM_VERSION" \
|
||||
-m "Source: $GITHUB_REPOSITORY@$GITHUB_SHA" \
|
||||
--allow-empty
|
||||
git push
|
||||
|
||||
echo "✅ CLI repo synced to version ${{ needs.generate-release.outputs.npm_version }}"
|
||||
echo "✅ CLI repo synced to version $NPM_VERSION"
|
||||
|
||||
- name: Sync version to SDK repository
|
||||
run: |
|
||||
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/sdk.git /tmp/sdk-repo
|
||||
cd /tmp/sdk-repo
|
||||
|
||||
jq --arg v "${{ needs.generate-release.outputs.npm_version }}" '.version = $v' package.json > package.json.tmp
|
||||
jq --arg v "$NPM_VERSION" '.version = $v' package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
|
||||
cp ${{ github.workspace }}/openapi.json ./openapi.json
|
||||
cp $GITHUB_WORKSPACE/openapi.json ./openapi.json
|
||||
pnpm install
|
||||
pnpm run generate
|
||||
|
||||
git config user.name "Dokploy Bot"
|
||||
git config user.email "bot@dokploy.com"
|
||||
git add -A
|
||||
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.npm_version }}" \
|
||||
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
|
||||
git commit -m "chore: bump version to $NPM_VERSION" \
|
||||
-m "Source: $GITHUB_REPOSITORY@$GITHUB_SHA" \
|
||||
--allow-empty
|
||||
git push
|
||||
|
||||
echo "✅ SDK repo synced to version ${{ needs.generate-release.outputs.npm_version }}"
|
||||
echo "✅ SDK repo synced to version $NPM_VERSION"
|
||||
|
||||
@@ -6,15 +6,20 @@ on:
|
||||
pull_request:
|
||||
branches: [canary]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup biomeJs
|
||||
uses: biomejs/setup-biome@v2
|
||||
uses: biomejs/setup-biome@v2
|
||||
|
||||
- name: Run Biome formatter
|
||||
run: biome format --write
|
||||
|
||||
@@ -16,17 +16,19 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.HOTFIX_PUSH_TOKEN }}
|
||||
|
||||
- name: Cherry-pick fix to main
|
||||
env:
|
||||
MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
run: |
|
||||
git config user.name "Dokploy Bot"
|
||||
git config user.email "bot@dokploy.com"
|
||||
SHA="${{ github.event.pull_request.merge_commit_sha }}"
|
||||
SHA="$MERGE_SHA"
|
||||
if [ "$(git rev-list --parents -n1 "$SHA" | wc -w)" -gt 2 ]; then
|
||||
git cherry-pick -x -m 1 "$SHA"
|
||||
else
|
||||
|
||||
@@ -7,12 +7,16 @@ concurrency:
|
||||
group: hotfix-to-main
|
||||
cancel-in-progress: false
|
||||
|
||||
# Push to main goes through HOTFIX_PUSH_TOKEN, not the workflow token.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ secrets.HOTFIX_PUSH_TOKEN }}
|
||||
|
||||
@@ -7,18 +7,23 @@ on:
|
||||
env:
|
||||
IMAGE_NAME: dokploy/monitoring
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docker-amd:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -26,17 +31,17 @@ jobs:
|
||||
- name: Set tag
|
||||
id: meta
|
||||
run: |
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
elif [ "${{ github.ref }}" = "refs/heads/canary" ]; then
|
||||
elif [ "$GITHUB_REF" = "refs/heads/canary" ]; then
|
||||
TAG="canary"
|
||||
else
|
||||
TAG="feature"
|
||||
fi
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-amd64" >> $GITHUB_OUTPUT
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-amd64" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.monitoring
|
||||
@@ -47,13 +52,15 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -61,17 +68,17 @@ jobs:
|
||||
- name: Set
|
||||
id: meta
|
||||
run: |
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
elif [ "${{ github.ref }}" = "refs/heads/canary" ]; then
|
||||
elif [ "$GITHUB_REF" = "refs/heads/canary" ]; then
|
||||
TAG="canary"
|
||||
else
|
||||
TAG="feature"
|
||||
fi
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-arm64" >> $GITHUB_OUTPUT
|
||||
echo "tags=${IMAGE_NAME}:${TAG}-arm64" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.monitoring
|
||||
@@ -84,27 +91,29 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Create and push manifests
|
||||
run: |
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
if [ "$GITHUB_REF" = "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
|
||||
docker buildx imagetools create -t ${IMAGE_NAME}:${TAG} \
|
||||
${IMAGE_NAME}:${TAG}-amd64 \
|
||||
${IMAGE_NAME}:${TAG}-arm64
|
||||
|
||||
elif [ "${{ github.ref }}" = "refs/heads/canary" ]; then
|
||||
elif [ "$GITHUB_REF" = "refs/heads/canary" ]; then
|
||||
TAG="canary"
|
||||
docker buildx imagetools create -t ${IMAGE_NAME}:${TAG} \
|
||||
${IMAGE_NAME}:${TAG}-amd64 \
|
||||
|
||||
@@ -14,9 +14,11 @@ jobs:
|
||||
matrix:
|
||||
job: [build, test, typecheck]
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: pnpm/action-setup@v5
|
||||
- uses: actions/setup-node@v5
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 24.4.0
|
||||
cache: "pnpm"
|
||||
|
||||
@@ -12,17 +12,20 @@ on:
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
generate-and-commit:
|
||||
name: Generate OpenAPI and commit to Dokploy repo
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Dokploy repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v4
|
||||
persist-credentials: false
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 24.4.0
|
||||
cache: "pnpm"
|
||||
|
||||
@@ -28,6 +28,9 @@ env:
|
||||
DOKPLOY_SERVICE: dokploy
|
||||
DOKPLOY_PORT: 3000
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
jobs:
|
||||
|
||||
@@ -421,8 +424,10 @@ jobs:
|
||||
# ── Job summary ────────────────────────────────────────────────────────
|
||||
- name: Write job summary
|
||||
if: always()
|
||||
env:
|
||||
JOB_STATUS: ${{ job.status }}
|
||||
run: |
|
||||
STATUS="${{ job.status }}"
|
||||
STATUS="$JOB_STATUS"
|
||||
ICON="✅"; [ "$STATUS" != "success" ] && ICON="❌"
|
||||
cat >> "$GITHUB_STEP_SUMMARY" <<EOF
|
||||
## ${ICON} ${{ matrix.pair.from }} → ${{ matrix.pair.to }}: ${STATUS^^}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import type { Compose, ComposeSpecification } from "@dokploy/server";
|
||||
import {
|
||||
addAppNameToPreventCollision,
|
||||
addSuffixToAllProperties,
|
||||
} from "@dokploy/server";
|
||||
import { addDomainToCompose } from "@dokploy/server/utils/docker/domain";
|
||||
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
|
||||
import { expect, test, vi } from "vitest";
|
||||
import { stringify } from "yaml";
|
||||
import composeSpec from "../../../components/shared/compose-spec.json";
|
||||
|
||||
vi.mock("@dokploy/server/utils/process/execAsync", async (importOriginal) => ({
|
||||
...(await importOriginal<
|
||||
typeof import("@dokploy/server/utils/process/execAsync")
|
||||
>()),
|
||||
execAsyncRemote: vi.fn(),
|
||||
}));
|
||||
|
||||
const modelCompose = {
|
||||
services: {
|
||||
app: {
|
||||
image: "my-chat-app",
|
||||
models: ["llm"],
|
||||
},
|
||||
worker: {
|
||||
image: "my-worker",
|
||||
models: {
|
||||
llm: {
|
||||
endpoint_var: "LLM_URL",
|
||||
model_var: "LLM_MODEL",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
models: {
|
||||
llm: {
|
||||
model: "ai/smollm2",
|
||||
context_size: 2048,
|
||||
runtime_flags: ["--verbose"],
|
||||
},
|
||||
},
|
||||
} satisfies ComposeSpecification;
|
||||
|
||||
test("bundled compose schema declares models", () => {
|
||||
expect(composeSpec.properties).toHaveProperty("models");
|
||||
expect(composeSpec.definitions.model.required).toEqual(["model"]);
|
||||
expect(composeSpec.definitions.service.properties).toHaveProperty("models");
|
||||
});
|
||||
|
||||
test("suffixing does not rename model identifiers or drop model config", () => {
|
||||
const updated = addSuffixToAllProperties(
|
||||
structuredClone(modelCompose),
|
||||
"testhash",
|
||||
);
|
||||
|
||||
expect(updated.models?.llm?.model).toBe("ai/smollm2");
|
||||
expect(updated.models?.llm?.context_size).toBe(2048);
|
||||
expect(updated.models?.llm?.runtime_flags).toEqual(["--verbose"]);
|
||||
expect(updated.services?.["app-testhash"]?.models).toEqual(["llm"]);
|
||||
expect(updated.services?.["worker-testhash"]?.models).toEqual({
|
||||
llm: {
|
||||
endpoint_var: "LLM_URL",
|
||||
model_var: "LLM_MODEL",
|
||||
},
|
||||
});
|
||||
expect(updated.services).not.toHaveProperty("app");
|
||||
expect(updated.models).not.toHaveProperty("llm-testhash");
|
||||
});
|
||||
|
||||
test("isolated deployment preserves model identifiers", () => {
|
||||
const updated = addAppNameToPreventCollision(
|
||||
structuredClone(modelCompose),
|
||||
"chat-app",
|
||||
false,
|
||||
);
|
||||
|
||||
expect(updated.models?.llm?.model).toBe("ai/smollm2");
|
||||
expect(updated.services?.app?.models).toEqual(["llm"]);
|
||||
expect(updated.services?.worker?.models).toEqual({
|
||||
llm: {
|
||||
endpoint_var: "LLM_URL",
|
||||
model_var: "LLM_MODEL",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("raw remote compose conversion preserves models", async () => {
|
||||
const converted = await addDomainToCompose(
|
||||
{
|
||||
appName: "chat-app",
|
||||
composeFile: stringify(modelCompose, { lineWidth: 1000 }),
|
||||
composePath: "./docker-compose.yml",
|
||||
composeType: "docker-compose",
|
||||
isolatedDeployment: false,
|
||||
isolatedDeploymentsVolume: false,
|
||||
randomize: false,
|
||||
serverId: "remote-server",
|
||||
sourceType: "raw",
|
||||
suffix: "",
|
||||
} as unknown as Compose,
|
||||
[],
|
||||
);
|
||||
|
||||
expect(execAsyncRemote).not.toHaveBeenCalled();
|
||||
expect(converted?.models?.llm?.model).toBe("ai/smollm2");
|
||||
expect(converted?.services?.app?.models).toEqual(["llm"]);
|
||||
expect(converted?.services?.worker?.models).toEqual({
|
||||
llm: {
|
||||
endpoint_var: "LLM_URL",
|
||||
model_var: "LLM_MODEL",
|
||||
},
|
||||
});
|
||||
});
|
||||
+71
@@ -472,6 +472,77 @@ describe("infisical client", () => {
|
||||
expect(params.get("secretPath")).toBe("/frontend");
|
||||
});
|
||||
|
||||
it("asks for imported secrets and merges them", async () => {
|
||||
mockFetch.mockResolvedValueOnce(loginResponse()).mockResolvedValueOnce(
|
||||
jsonResponse({
|
||||
secrets: [],
|
||||
imports: [
|
||||
{
|
||||
secretPath: "/shared",
|
||||
secrets: [
|
||||
{ secretKey: "DB_URL", secretValue: "postgres://imported" },
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await infisicalClient.getSecrets(config, ["DB_URL"]);
|
||||
|
||||
expect(result).toEqual({ DB_URL: "postgres://imported" });
|
||||
const [listUrl] = mockFetch.mock.calls[1] as [string];
|
||||
// snake_case on purpose: `includeImports` is silently ignored and the
|
||||
// response comes back with an empty `imports` array.
|
||||
expect(new URL(listUrl).searchParams.get("include_imports")).toBe("true");
|
||||
});
|
||||
|
||||
it("lets the later import win when two define the same key", async () => {
|
||||
mockFetch.mockResolvedValueOnce(loginResponse()).mockResolvedValueOnce(
|
||||
jsonResponse({
|
||||
secrets: [],
|
||||
imports: [
|
||||
{
|
||||
secretPath: "/base",
|
||||
secrets: [{ secretKey: "DB_URL", secretValue: "postgres://base" }],
|
||||
},
|
||||
{
|
||||
secretPath: "/override",
|
||||
secrets: [
|
||||
{ secretKey: "DB_URL", secretValue: "postgres://override" },
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await infisicalClient.getSecrets(config, ["DB_URL"]);
|
||||
|
||||
// Infisical documents this order: "If two imports carry a secret with the
|
||||
// same name, the value from the bottom-most import wins." The response
|
||||
// lists imports in that order, so assigning them in sequence matches it.
|
||||
expect(result).toEqual({ DB_URL: "postgres://override" });
|
||||
});
|
||||
|
||||
it("lets a folder's own secret win over an imported one of the same name", async () => {
|
||||
mockFetch.mockResolvedValueOnce(loginResponse()).mockResolvedValueOnce(
|
||||
jsonResponse({
|
||||
secrets: [{ secretKey: "DB_URL", secretValue: "postgres://local" }],
|
||||
imports: [
|
||||
{
|
||||
secretPath: "/shared",
|
||||
secrets: [
|
||||
{ secretKey: "DB_URL", secretValue: "postgres://imported" },
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await infisicalClient.getSecrets(config, ["DB_URL"]);
|
||||
|
||||
expect(result).toEqual({ DB_URL: "postgres://local" });
|
||||
});
|
||||
|
||||
it("throws a clear error for a missing secret", async () => {
|
||||
mockFetch
|
||||
.mockResolvedValueOnce(loginResponse())
|
||||
|
||||
@@ -31,6 +31,45 @@ import { api } from "@/utils/api";
|
||||
|
||||
// Railpack versions from https://github.com/railwayapp/railpack/releases
|
||||
export const RAILPACK_VERSIONS = [
|
||||
"0.39.0",
|
||||
"0.38.0",
|
||||
"0.37.1",
|
||||
"0.37.0",
|
||||
"0.36.4",
|
||||
"0.36.3",
|
||||
"0.36.2",
|
||||
"0.36.1",
|
||||
"0.36.0",
|
||||
"0.35.0",
|
||||
"0.34.0",
|
||||
"0.33.0",
|
||||
"0.32.0",
|
||||
"0.31.2",
|
||||
"0.31.1",
|
||||
"0.31.0",
|
||||
"0.30.1",
|
||||
"0.30.0",
|
||||
"0.29.0",
|
||||
"0.28.0",
|
||||
"0.27.2",
|
||||
"0.27.1",
|
||||
"0.27.0",
|
||||
"0.26.1",
|
||||
"0.26.0",
|
||||
"0.25.0",
|
||||
"0.24.0",
|
||||
"0.23.0",
|
||||
"0.22.2",
|
||||
"0.22.1",
|
||||
"0.22.0",
|
||||
"0.21.0",
|
||||
"0.20.0",
|
||||
"0.19.0",
|
||||
"0.18.0",
|
||||
"0.17.2",
|
||||
"0.17.1",
|
||||
"0.17.0",
|
||||
"0.16.0",
|
||||
"0.15.4",
|
||||
"0.15.3",
|
||||
"0.15.2",
|
||||
@@ -45,12 +84,22 @@ export const RAILPACK_VERSIONS = [
|
||||
"0.9.1",
|
||||
"0.9.0",
|
||||
"0.8.0",
|
||||
"0.7.2",
|
||||
"0.7.1",
|
||||
"0.7.0",
|
||||
"0.6.1",
|
||||
"0.6.0",
|
||||
"0.5.1",
|
||||
"0.5.0",
|
||||
"0.4.0",
|
||||
"0.3.0",
|
||||
"0.2.3",
|
||||
"0.2.2",
|
||||
"0.2.1",
|
||||
"0.2.0",
|
||||
"0.1.2",
|
||||
"0.1.1",
|
||||
"0.1.0",
|
||||
] as const;
|
||||
|
||||
export enum BuildType {
|
||||
|
||||
@@ -6,28 +6,41 @@ import { api } from "@/utils/api";
|
||||
export const TrialBanner = () => {
|
||||
const router = useRouter();
|
||||
const { data: billingStatus } = api.stripe.getBillingStatus.useQuery();
|
||||
const { mutateAsync: createCustomerPortalSession, isPending } =
|
||||
api.stripe.createCustomerPortalSession.useMutation();
|
||||
|
||||
if (!billingStatus?.isOnTrial) {
|
||||
const handleAddPaymentMethod = async () => {
|
||||
const session = await createCustomerPortalSession().catch(() => null);
|
||||
if (session?.url) {
|
||||
window.open(session.url);
|
||||
return;
|
||||
}
|
||||
router.push("/dashboard/settings/billing");
|
||||
};
|
||||
|
||||
if (!billingStatus?.isOnTrial || billingStatus.hasPaymentMethod) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const daysRemaining = billingStatus.trialDaysRemaining ?? 0;
|
||||
const daysLabel = `${daysRemaining} day${daysRemaining === 1 ? "" : "s"}`;
|
||||
|
||||
return (
|
||||
<div className="sticky top-0 z-20 mx-4 mt-4 flex flex-wrap items-center justify-center gap-x-3 gap-y-2 rounded-lg border border-primary/20 bg-primary/10 px-4 py-2 text-sm">
|
||||
<span className="flex items-center gap-2">
|
||||
<Rocket className="h-4 w-4 text-primary shrink-0" />
|
||||
{daysRemaining > 0
|
||||
? `You have ${daysRemaining} day${daysRemaining === 1 ? "" : "s"} left in your free trial.`
|
||||
: "Your free trial ends today."}
|
||||
? `You have ${daysLabel} left in your free trial. Add a payment method to keep your servers.`
|
||||
: "Your free trial ends today. Add a payment method to keep your servers."}
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="default"
|
||||
className="h-7"
|
||||
onClick={() => router.push("/dashboard/settings/billing")}
|
||||
isLoading={isPending}
|
||||
onClick={handleAddPaymentMethod}
|
||||
>
|
||||
Upgrade now
|
||||
Add payment method
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -278,8 +278,9 @@ export const OnboardingWizard = ({ onClose }: Props) => {
|
||||
<DialogTitle>Skip onboarding?</DialogTitle>
|
||||
<DialogDescription>
|
||||
If this is your first time using Dokploy, we recommend going
|
||||
through these steps — it only takes a couple of minutes and gives
|
||||
you a feel for how projects, servers and deployments fit together.
|
||||
through these steps – it only takes a couple of minutes and gives
|
||||
you a feel for how projects, servers, and deployments fit
|
||||
together.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
|
||||
@@ -15,13 +15,50 @@ const stripePromise = loadStripe(
|
||||
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
|
||||
);
|
||||
|
||||
type Tier = "hobby" | "startup";
|
||||
|
||||
const PLANS: {
|
||||
tier: Tier;
|
||||
name: string;
|
||||
description: string;
|
||||
price: number;
|
||||
features: string[];
|
||||
recommended?: boolean;
|
||||
}[] = [
|
||||
{
|
||||
tier: "hobby",
|
||||
name: "Hobby",
|
||||
description: "For individual developers",
|
||||
price: calculatePriceHobby(1, false),
|
||||
features: [
|
||||
"Setup 1 server",
|
||||
"Unlimited apps & databases",
|
||||
"2 environments",
|
||||
"Community support",
|
||||
],
|
||||
},
|
||||
{
|
||||
tier: "startup",
|
||||
name: "Startup",
|
||||
description: "For small to mid-size teams",
|
||||
price: calculatePriceStartup(STARTUP_SERVERS_INCLUDED, false),
|
||||
recommended: true,
|
||||
features: [
|
||||
`Setup up to ${STARTUP_SERVERS_INCLUDED} servers`,
|
||||
"Unlimited users & environments",
|
||||
"Basic RBAC + 2FA",
|
||||
"Email & chat support",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
interface Props {
|
||||
onNext: () => void;
|
||||
}
|
||||
|
||||
export const PlanStep = ({ onNext }: Props) => {
|
||||
const [loadingTier, setLoadingTier] = useState<
|
||||
"hobby" | "startup" | "trial" | null
|
||||
const [loading, setLoading] = useState<
|
||||
`${"trial" | "checkout"}:${Tier}` | null
|
||||
>(null);
|
||||
const { data } = api.stripe.getProducts.useQuery();
|
||||
const { mutateAsync: createCheckoutSession } =
|
||||
@@ -30,12 +67,12 @@ export const PlanStep = ({ onNext }: Props) => {
|
||||
api.stripe.startFreeTrial.useMutation();
|
||||
const utils = api.useUtils();
|
||||
|
||||
const handleCheckout = async (tier: "hobby" | "startup") => {
|
||||
const handleCheckout = async (tier: Tier) => {
|
||||
if (!data) return;
|
||||
const productId =
|
||||
tier === "hobby" ? data.hobbyProductId : data.startupProductId;
|
||||
if (!productId) return;
|
||||
setLoadingTier(tier);
|
||||
setLoading(`checkout:${tier}`);
|
||||
try {
|
||||
const stripe = await stripePromise;
|
||||
const session = await createCheckoutSession({
|
||||
@@ -47,14 +84,14 @@ export const PlanStep = ({ onNext }: Props) => {
|
||||
await stripe?.redirectToCheckout({ sessionId: session.sessionId });
|
||||
} catch {
|
||||
toast.error("Error starting checkout");
|
||||
setLoadingTier(null);
|
||||
setLoading(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTrial = async () => {
|
||||
setLoadingTier("trial");
|
||||
const handleTrial = async (tier: Tier) => {
|
||||
setLoading(`trial:${tier}`);
|
||||
try {
|
||||
await startFreeTrial();
|
||||
await startFreeTrial({ tier });
|
||||
await utils.project.onboardingStatus.invalidate();
|
||||
toast.success("Your 7-day trial has started");
|
||||
onNext();
|
||||
@@ -63,7 +100,7 @@ export const PlanStep = ({ onNext }: Props) => {
|
||||
error instanceof Error ? error.message : "Error starting trial",
|
||||
);
|
||||
} finally {
|
||||
setLoadingTier(null);
|
||||
setLoading(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -79,134 +116,72 @@ export const PlanStep = ({ onNext }: Props) => {
|
||||
Start free, upgrade when ready.
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-lg max-w-md leading-relaxed">
|
||||
No credit card for the trial — add one only if you decide to stay.
|
||||
Try any plan free for 7 days. No credit card required — add one only
|
||||
if you decide to stay.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col rounded-2xl bg-zinc-950 dark:bg-white text-white dark:text-zinc-950 overflow-hidden">
|
||||
<div className="flex flex-col sm:flex-row sm:items-start justify-between gap-6 p-7">
|
||||
<div>
|
||||
<span className="inline-flex items-center rounded-full bg-white text-zinc-950 dark:bg-zinc-950 dark:text-white font-mono text-[10px] font-semibold uppercase tracking-[0.15em] px-2.5 py-1">
|
||||
Recommended
|
||||
</span>
|
||||
<p className={`${displayFont.className} text-2xl mt-3`}>
|
||||
7-day free trial
|
||||
</p>
|
||||
<p className="text-sm text-zinc-400 dark:text-zinc-600 mt-1 max-w-xs">
|
||||
No card required — cancel anytime.
|
||||
</p>
|
||||
<ul className="flex flex-col gap-1.5 mt-4">
|
||||
{[
|
||||
"Setup 1 server",
|
||||
"Unlimited apps & databases",
|
||||
"Community support",
|
||||
].map((f) => (
|
||||
<li
|
||||
key={f}
|
||||
className="flex items-center gap-2 text-sm text-zinc-300 dark:text-zinc-700"
|
||||
>
|
||||
<CheckIcon className="size-3.5 text-zinc-500 shrink-0" />
|
||||
{f}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<Button
|
||||
size="lg"
|
||||
className="bg-white text-zinc-950 hover:bg-zinc-200 dark:bg-zinc-950 dark:text-white dark:hover:bg-zinc-800 w-fit shrink-0 px-6"
|
||||
isLoading={loadingTier === "trial"}
|
||||
disabled={loadingTier !== null}
|
||||
onClick={handleTrial}
|
||||
>
|
||||
Start trial
|
||||
<ArrowRightIcon className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-px bg-border rounded-2xl overflow-hidden border">
|
||||
<div className="flex flex-col justify-between gap-6 bg-background p-7">
|
||||
<div>
|
||||
<p className="font-medium">Hobby</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
For individual developers
|
||||
</p>
|
||||
<p className="text-3xl font-semibold mt-4 tabular-nums">
|
||||
${calculatePriceHobby(1, false).toFixed(2)}
|
||||
<span className="text-sm font-normal text-muted-foreground">
|
||||
{" "}
|
||||
/mo
|
||||
</span>
|
||||
</p>
|
||||
<ul className="flex flex-col gap-1.5 mt-4">
|
||||
{[
|
||||
"Setup 1 server",
|
||||
"Unlimited apps & databases",
|
||||
"2 environments",
|
||||
"Community support",
|
||||
].map((f) => (
|
||||
<li
|
||||
key={f}
|
||||
className="flex items-center gap-2 text-sm text-muted-foreground"
|
||||
{PLANS.map((plan) => {
|
||||
const productId =
|
||||
plan.tier === "hobby"
|
||||
? data?.hobbyProductId
|
||||
: data?.startupProductId;
|
||||
return (
|
||||
<div
|
||||
key={plan.tier}
|
||||
className="flex flex-col justify-between gap-6 bg-background p-7"
|
||||
>
|
||||
<div>
|
||||
{plan.recommended && (
|
||||
<span className="inline-flex items-center rounded-full bg-primary text-primary-foreground font-mono text-[10px] font-semibold uppercase tracking-[0.15em] px-2.5 py-1 mb-3">
|
||||
Recommended
|
||||
</span>
|
||||
)}
|
||||
<p className="font-medium">{plan.name}</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{plan.description}
|
||||
</p>
|
||||
<p className="text-3xl font-semibold mt-4 tabular-nums">
|
||||
${plan.price.toFixed(2)}
|
||||
<span className="text-sm font-normal text-muted-foreground">
|
||||
{" "}
|
||||
/mo
|
||||
</span>
|
||||
</p>
|
||||
<ul className="flex flex-col gap-1.5 mt-4">
|
||||
{plan.features.map((f) => (
|
||||
<li
|
||||
key={f}
|
||||
className="flex items-center gap-2 text-sm text-muted-foreground"
|
||||
>
|
||||
<CheckIcon className="size-3.5 shrink-0" />
|
||||
{f}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button
|
||||
isLoading={loading === `trial:${plan.tier}`}
|
||||
disabled={loading !== null}
|
||||
onClick={() => handleTrial(plan.tier)}
|
||||
>
|
||||
<CheckIcon className="size-3.5 shrink-0" />
|
||||
{f}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
isLoading={loadingTier === "hobby"}
|
||||
disabled={loadingTier !== null || !data?.hobbyProductId}
|
||||
onClick={() => handleCheckout("hobby")}
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-between gap-6 bg-background p-7">
|
||||
<div>
|
||||
<p className="font-medium">Startup</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
For small to mid-size teams
|
||||
</p>
|
||||
<p className="text-3xl font-semibold mt-4 tabular-nums">
|
||||
$
|
||||
{calculatePriceStartup(STARTUP_SERVERS_INCLUDED, false).toFixed(
|
||||
2,
|
||||
)}
|
||||
<span className="text-sm font-normal text-muted-foreground">
|
||||
{" "}
|
||||
/mo
|
||||
</span>
|
||||
</p>
|
||||
<ul className="flex flex-col gap-1.5 mt-4">
|
||||
{[
|
||||
`Setup up to ${STARTUP_SERVERS_INCLUDED} servers`,
|
||||
"Unlimited users & environments",
|
||||
"Basic RBAC + 2FA",
|
||||
"Email & chat support",
|
||||
].map((f) => (
|
||||
<li
|
||||
key={f}
|
||||
className="flex items-center gap-2 text-sm text-muted-foreground"
|
||||
Start 7-day free trial
|
||||
<ArrowRightIcon className="size-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
isLoading={loading === `checkout:${plan.tier}`}
|
||||
disabled={loading !== null || !productId}
|
||||
onClick={() => handleCheckout(plan.tier)}
|
||||
>
|
||||
<CheckIcon className="size-3.5 shrink-0" />
|
||||
{f}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
isLoading={loadingTier === "startup"}
|
||||
disabled={loadingTier !== null || !data?.startupProductId}
|
||||
onClick={() => handleCheckout("startup")}
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
</div>
|
||||
Subscribe now
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ export const ProjectStep = ({ onNext, plainTitle }: Props) => {
|
||||
</span>
|
||||
<h1 className={titleClassName}>Create your first project.</h1>
|
||||
<p className="text-muted-foreground text-lg max-w-md leading-relaxed">
|
||||
Projects group your apps, databases and environments together.
|
||||
Projects group your apps, databases, and environments together.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
|
||||
import copy from "copy-to-clipboard";
|
||||
import { CheckCircle2, CopyIcon, Loader2, XCircle } from "lucide-react";
|
||||
import {
|
||||
CheckCircle2,
|
||||
CopyIcon,
|
||||
InfoIcon,
|
||||
Loader2,
|
||||
XCircle,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
@@ -200,9 +206,19 @@ export const ServerStep = ({ onNext, plainTitle }: Props) => {
|
||||
</span>
|
||||
<h1 className={titleClassName}>Connect a server.</h1>
|
||||
<p className="text-muted-foreground text-lg max-w-md leading-relaxed">
|
||||
Dokploy deploys to servers you own — buy one from any VPS provider
|
||||
Dokploy deploys to servers you own. Buy one from any VPS provider
|
||||
(Hetzner, DigitalOcean, Hostinger...) and paste its IP below.
|
||||
</p>
|
||||
<div className="flex items-start gap-2.5 rounded-lg border p-3 max-w-md">
|
||||
<InfoIcon className="size-4 text-muted-foreground shrink-0 mt-0.5" />
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-sm font-medium">Requirements</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
To ensure a smooth experience with Dokploy, your server should
|
||||
have at least 1GB of RAM and 30GB of disk space.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!createdServerId ? (
|
||||
@@ -287,7 +303,7 @@ export const ServerStep = ({ onNext, plainTitle }: Props) => {
|
||||
{isSettingUp ? (
|
||||
<div className="flex items-center justify-center gap-3 py-4 text-sm text-muted-foreground">
|
||||
<Loader2 className="size-4 animate-spin shrink-0" />
|
||||
Setting up your server — installing Docker and dependencies...
|
||||
Setting up your server – installing Docker and dependencies…
|
||||
</div>
|
||||
) : isValidating && !validation ? (
|
||||
<div className="flex items-center justify-center gap-2 py-4 text-sm text-muted-foreground">
|
||||
@@ -311,7 +327,7 @@ export const ServerStep = ({ onNext, plainTitle }: Props) => {
|
||||
</div>
|
||||
{!isReady && !isSettingUp && (
|
||||
<AlertBlock type="info">
|
||||
Setup usually takes a minute after the server boots — this checks
|
||||
Setup runs after the server boots and this page checks for it
|
||||
automatically. You can retry setup, or use "Skip for now" above to
|
||||
continue and come back to this later.
|
||||
</AlertBlock>
|
||||
|
||||
@@ -39,8 +39,8 @@ export const WelcomeStep = ({ onNext }: Props) => {
|
||||
Let's get your first app <em className="not-italic">live</em>.
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-lg max-w-md leading-relaxed">
|
||||
A few steps — pick a plan, connect a server, ship something. You'll
|
||||
have a working URL by the end.
|
||||
It just takes a few steps: pick a plan, connect a server, ship
|
||||
something. You'll have a working URL by the end.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -105,13 +105,47 @@ export const ShowBilling = () => {
|
||||
api.stripe.upgradeSubscription.useMutation();
|
||||
const { mutateAsync: updateInvoiceNotifications } =
|
||||
api.stripe.updateInvoiceNotifications.useMutation();
|
||||
const { mutateAsync: startFreeTrial, isPending: isStartingTrial } =
|
||||
const { mutateAsync: startFreeTrial } =
|
||||
api.stripe.startFreeTrial.useMutation();
|
||||
const utils = api.useUtils();
|
||||
const [trialTier, setTrialTier] = useState<"hobby" | "startup" | null>(null);
|
||||
const [switchingTrial, setSwitchingTrial] = useState(false);
|
||||
|
||||
const handleStartTrial = async () => {
|
||||
const handleSwitchTrialPlan = async (tier: "hobby" | "startup") => {
|
||||
const planName = tier === "startup" ? "Startup" : "Hobby";
|
||||
|
||||
const switchPlan = async () => {
|
||||
await upgradeSubscription({
|
||||
tier,
|
||||
serverQuantity: tier === "startup" ? STARTUP_SERVERS_INCLUDED : 1,
|
||||
isAnnual: false,
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
await Promise.all([
|
||||
utils.stripe.getBillingStatus.invalidate(),
|
||||
utils.stripe.getProducts.invalidate(),
|
||||
utils.user.get.invalidate(),
|
||||
utils.server.count.invalidate(),
|
||||
]);
|
||||
};
|
||||
|
||||
setSwitchingTrial(true);
|
||||
await toast
|
||||
.promise(switchPlan(), {
|
||||
loading: `Switching to ${planName}...`,
|
||||
success: `Your trial is now on the ${planName} plan`,
|
||||
error: (error) =>
|
||||
error instanceof Error ? error.message : "Error switching plan",
|
||||
})
|
||||
.unwrap()
|
||||
.catch(() => undefined);
|
||||
setSwitchingTrial(false);
|
||||
};
|
||||
|
||||
const handleStartTrial = async (tier: "hobby" | "startup") => {
|
||||
setTrialTier(tier);
|
||||
try {
|
||||
await startFreeTrial();
|
||||
await startFreeTrial({ tier });
|
||||
await Promise.all([
|
||||
utils.stripe.getBillingStatus.invalidate(),
|
||||
utils.stripe.getProducts.invalidate(),
|
||||
@@ -122,6 +156,8 @@ export const ShowBilling = () => {
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Error starting trial",
|
||||
);
|
||||
} finally {
|
||||
setTrialTier(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,12 +206,23 @@ export const ShowBilling = () => {
|
||||
|
||||
const useNewPricing = data?.hobbyProductId && data?.startupProductId;
|
||||
const products = data?.products.filter((product) => {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const interval = product?.default_price?.recurring?.interval;
|
||||
return isAnnual ? interval === "year" : interval === "month";
|
||||
});
|
||||
|
||||
const isEnterpriseCloud = admin?.user.isEnterpriseCloud ?? false;
|
||||
const canStartTrial =
|
||||
!isEnterpriseCloud &&
|
||||
!!billingStatus &&
|
||||
!billingStatus.plan &&
|
||||
!billingStatus.isOnTrial &&
|
||||
!billingStatus.hasUsedTrial;
|
||||
/** Checkout would create a second subscription alongside a running trial. */
|
||||
const canSubscribe =
|
||||
!isEnterpriseCloud &&
|
||||
(data?.subscriptions?.length ?? 0) === 0 &&
|
||||
!billingStatus?.isOnTrial;
|
||||
const maxServers = admin?.user.serversQuantity ?? 1;
|
||||
const percentage = ((servers ?? 0) / maxServers) * 100;
|
||||
const safePercentage = Math.min(percentage, 100);
|
||||
@@ -296,67 +343,72 @@ export const ShowBilling = () => {
|
||||
billingStatus.trialEndsAt
|
||||
? ` · ends ${new Date(billingStatus.trialEndsAt).toLocaleDateString()}`
|
||||
: ""
|
||||
}${
|
||||
billingStatus.hasPaymentMethod
|
||||
? " · billing starts automatically"
|
||||
: " · add a card to keep your servers"
|
||||
}`
|
||||
: "You're subscribed and billed automatically."}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{billingStatus.isOnTrial &&
|
||||
admin?.user.stripeCustomerId && (
|
||||
{admin?.user.stripeCustomerId && (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{billingStatus.isOnTrial &&
|
||||
useNewPricing &&
|
||||
billingStatus.plan && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
isLoading={switchingTrial}
|
||||
onClick={() =>
|
||||
handleSwitchTrialPlan(
|
||||
billingStatus.plan === "startup"
|
||||
? "hobby"
|
||||
: "startup",
|
||||
)
|
||||
}
|
||||
>
|
||||
{billingStatus.plan === "startup"
|
||||
? "Switch to Hobby"
|
||||
: "Switch to Startup"}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
variant={
|
||||
billingStatus.isOnTrial &&
|
||||
!billingStatus.hasPaymentMethod
|
||||
? "default"
|
||||
: "secondary"
|
||||
}
|
||||
onClick={async () => {
|
||||
const session = await createCustomerPortalSession();
|
||||
window.open(session.url);
|
||||
}}
|
||||
>
|
||||
Add payment method
|
||||
{billingStatus.isOnTrial &&
|
||||
!billingStatus.hasPaymentMethod
|
||||
? "Add payment method"
|
||||
: "Manage Subscription"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!isEnterpriseCloud &&
|
||||
billingStatus &&
|
||||
!billingStatus.plan &&
|
||||
!billingStatus.isOnTrial &&
|
||||
!billingStatus.hasUsedTrial && (
|
||||
<div className="flex flex-wrap items-center justify-between gap-4 rounded-xl border border-primary/30 bg-primary/5 p-4 max-w-2xl">
|
||||
<div className="flex items-center gap-3">
|
||||
<Clock className="h-5 w-5 text-primary shrink-0" />
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<span className="text-sm font-medium">
|
||||
7-day free trial
|
||||
</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
No credit card required — cancel anytime.
|
||||
</span>
|
||||
<ul className="flex flex-col gap-1 mt-1">
|
||||
{[
|
||||
"Setup 1 server",
|
||||
"Unlimited apps & databases",
|
||||
"Community support",
|
||||
].map((feature) => (
|
||||
<li
|
||||
key={feature}
|
||||
className="flex items-center gap-2 text-sm text-muted-foreground"
|
||||
>
|
||||
<CheckIcon className="size-3.5 shrink-0" />
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
isLoading={isStartingTrial}
|
||||
onClick={handleStartTrial}
|
||||
>
|
||||
Start trial
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{canStartTrial && (
|
||||
<div className="flex items-center gap-3 rounded-xl border border-primary/30 bg-primary/5 p-4 max-w-2xl">
|
||||
<Clock className="h-5 w-5 text-primary shrink-0" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-medium">
|
||||
7-day free trial on any plan
|
||||
</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
No credit card required — pick Hobby or Startup below.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(admin?.user.stripeSubscriptionId || isEnterpriseCloud) && (
|
||||
<div className="space-y-2 flex flex-col">
|
||||
<h3 className="text-lg font-medium">Servers Plan</h3>
|
||||
@@ -933,68 +985,71 @@ export const ShowBilling = () => {
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-6 flex flex-col gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Servers:
|
||||
</span>
|
||||
<Button
|
||||
disabled={hobbyServerQuantity <= 1}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() =>
|
||||
setHobbyServerQuantity((q) => Math.max(1, q - 1))
|
||||
}
|
||||
>
|
||||
<MinusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<NumberInput
|
||||
value={hobbyServerQuantity}
|
||||
onChange={(e) =>
|
||||
setHobbyServerQuantity(
|
||||
Math.max(
|
||||
1,
|
||||
Number(
|
||||
(e.target as HTMLInputElement).value,
|
||||
) || 1,
|
||||
),
|
||||
)
|
||||
}
|
||||
className="text-center"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => setHobbyServerQuantity((q) => q + 1)}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
{admin?.user.stripeCustomerId && (
|
||||
{canSubscribe && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Servers:
|
||||
</span>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
onClick={async () => {
|
||||
const session =
|
||||
await createCustomerPortalSession();
|
||||
window.open(session.url);
|
||||
}}
|
||||
disabled={hobbyServerQuantity <= 1}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() =>
|
||||
setHobbyServerQuantity((q) =>
|
||||
Math.max(1, q - 1),
|
||||
)
|
||||
}
|
||||
>
|
||||
Manage Subscription
|
||||
<MinusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<NumberInput
|
||||
value={hobbyServerQuantity}
|
||||
onChange={(e) =>
|
||||
setHobbyServerQuantity(
|
||||
Math.max(
|
||||
1,
|
||||
Number(
|
||||
(e.target as HTMLInputElement).value,
|
||||
) || 1,
|
||||
),
|
||||
)
|
||||
}
|
||||
className="text-center"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() =>
|
||||
setHobbyServerQuantity((q) => q + 1)
|
||||
}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
{canStartTrial && (
|
||||
<Button
|
||||
className="w-full"
|
||||
isLoading={trialTier === "hobby"}
|
||||
disabled={trialTier !== null}
|
||||
onClick={() => handleStartTrial("hobby")}
|
||||
>
|
||||
Start 7-day free trial
|
||||
</Button>
|
||||
)}
|
||||
{canSubscribe && (
|
||||
<Button
|
||||
className="w-full"
|
||||
variant={canStartTrial ? "outline" : "default"}
|
||||
onClick={() =>
|
||||
handleCheckout("hobby", data!.hobbyProductId!)
|
||||
}
|
||||
disabled={hobbyServerQuantity < 1}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
)}
|
||||
{!isEnterpriseCloud &&
|
||||
(data?.subscriptions?.length ?? 0) === 0 && (
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={() =>
|
||||
handleCheckout("hobby", data!.hobbyProductId!)
|
||||
}
|
||||
disabled={hobbyServerQuantity < 1}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1067,85 +1122,83 @@ export const ShowBilling = () => {
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-6 flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
Servers (min. {STARTUP_SERVERS_INCLUDED} included)
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
disabled={
|
||||
startupServerQuantity <=
|
||||
STARTUP_SERVERS_INCLUDED
|
||||
}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
onClick={() =>
|
||||
setStartupServerQuantity((q) =>
|
||||
Math.max(STARTUP_SERVERS_INCLUDED, q - 1),
|
||||
)
|
||||
}
|
||||
>
|
||||
<MinusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<NumberInput
|
||||
value={startupServerQuantity}
|
||||
onChange={(e) =>
|
||||
setStartupServerQuantity(
|
||||
Math.max(
|
||||
STARTUP_SERVERS_INCLUDED,
|
||||
Number(
|
||||
(e.target as HTMLInputElement).value,
|
||||
) || STARTUP_SERVERS_INCLUDED,
|
||||
),
|
||||
)
|
||||
}
|
||||
className="h-8 text-center"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
onClick={() =>
|
||||
setStartupServerQuantity((q) => q + 1)
|
||||
}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
{admin?.user.stripeCustomerId && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
onClick={async () => {
|
||||
const session =
|
||||
await createCustomerPortalSession();
|
||||
window.open(session.url);
|
||||
}}
|
||||
>
|
||||
Manage Subscription
|
||||
</Button>
|
||||
)}
|
||||
{!isEnterpriseCloud &&
|
||||
(data?.subscriptions?.length ?? 0) === 0 && (
|
||||
{canSubscribe && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
Servers (min. {STARTUP_SERVERS_INCLUDED} included)
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={() =>
|
||||
handleCheckout(
|
||||
"startup",
|
||||
data!.startupProductId!,
|
||||
)
|
||||
}
|
||||
disabled={
|
||||
startupServerQuantity <
|
||||
startupServerQuantity <=
|
||||
STARTUP_SERVERS_INCLUDED
|
||||
}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
onClick={() =>
|
||||
setStartupServerQuantity((q) =>
|
||||
Math.max(STARTUP_SERVERS_INCLUDED, q - 1),
|
||||
)
|
||||
}
|
||||
>
|
||||
Get Started
|
||||
<MinusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
<NumberInput
|
||||
value={startupServerQuantity}
|
||||
onChange={(e) =>
|
||||
setStartupServerQuantity(
|
||||
Math.max(
|
||||
STARTUP_SERVERS_INCLUDED,
|
||||
Number(
|
||||
(e.target as HTMLInputElement).value,
|
||||
) || STARTUP_SERVERS_INCLUDED,
|
||||
),
|
||||
)
|
||||
}
|
||||
className="h-8 text-center"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
onClick={() =>
|
||||
setStartupServerQuantity((q) => q + 1)
|
||||
}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
{canStartTrial && (
|
||||
<Button
|
||||
className="w-full"
|
||||
isLoading={trialTier === "startup"}
|
||||
disabled={trialTier !== null}
|
||||
onClick={() => handleStartTrial("startup")}
|
||||
>
|
||||
Start 7-day free trial
|
||||
</Button>
|
||||
)}
|
||||
{canSubscribe && (
|
||||
<Button
|
||||
className="w-full"
|
||||
variant={canStartTrial ? "outline" : "default"}
|
||||
onClick={() =>
|
||||
handleCheckout(
|
||||
"startup",
|
||||
data!.startupProductId!,
|
||||
)
|
||||
}
|
||||
disabled={
|
||||
startupServerQuantity < STARTUP_SERVERS_INCLUDED
|
||||
}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1337,31 +1390,17 @@ export const ShowBilling = () => {
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 mt-4 w-full">
|
||||
{admin?.user.stripeCustomerId && (
|
||||
{canSubscribe && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
onClick={async () => {
|
||||
const session =
|
||||
await createCustomerPortalSession();
|
||||
window.open(session.url);
|
||||
handleCheckout("legacy", product.id);
|
||||
}}
|
||||
disabled={hobbyServerQuantity < 1}
|
||||
>
|
||||
Manage Subscription
|
||||
Subscribe
|
||||
</Button>
|
||||
)}
|
||||
{!isEnterpriseCloud &&
|
||||
(data?.subscriptions?.length ?? 0) === 0 && (
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={async () => {
|
||||
handleCheckout("legacy", product.id);
|
||||
}}
|
||||
disabled={hobbyServerQuantity < 1}
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -30,6 +30,7 @@ const dockerComposeServices = [
|
||||
{ label: "networks", type: "keyword", info: "Define networks" },
|
||||
{ label: "configs", type: "keyword", info: "Define configuration files" },
|
||||
{ label: "secrets", type: "keyword", info: "Define secrets" },
|
||||
{ label: "models", type: "keyword", info: "Define AI models" },
|
||||
].map((opt) => ({
|
||||
...opt,
|
||||
apply: (
|
||||
@@ -83,6 +84,11 @@ const dockerComposeServiceOptions = [
|
||||
},
|
||||
{ label: "restart", type: "keyword", info: "Restart policy" },
|
||||
{ label: "networks", type: "keyword", info: "Networks to join" },
|
||||
{
|
||||
label: "models",
|
||||
type: "keyword",
|
||||
info: "AI models to use, referencing top-level models",
|
||||
},
|
||||
].map((opt) => ({
|
||||
...opt,
|
||||
apply: (
|
||||
|
||||
@@ -35,6 +35,16 @@
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"models": {
|
||||
"id": "#/properties/models",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/model"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"networks": {
|
||||
"id": "#/properties/networks",
|
||||
"type": "object",
|
||||
@@ -335,6 +345,30 @@
|
||||
"mem_swappiness": { "type": ["integer", "string"] },
|
||||
"memswap_limit": { "type": ["number", "string"] },
|
||||
"network_mode": { "type": "string" },
|
||||
"models": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/list_of_strings" },
|
||||
{
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"endpoint_var": { "type": "string" },
|
||||
"model_var": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": { "^x-": {} }
|
||||
},
|
||||
{ "type": "null" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"networks": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/list_of_strings" },
|
||||
@@ -890,6 +924,23 @@
|
||||
"patternProperties": { "^x-": {} }
|
||||
},
|
||||
|
||||
"model": {
|
||||
"id": "#/definitions/model",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"model": { "type": "string" },
|
||||
"context_size": { "type": "integer" },
|
||||
"runtime_flags": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"required": ["model"],
|
||||
"additionalProperties": false,
|
||||
"patternProperties": { "^x-": {} }
|
||||
},
|
||||
|
||||
"command": {
|
||||
"oneOf": [
|
||||
{ "type": "null" },
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
"lucide-react": "^0.469.0",
|
||||
"micromatch": "4.0.8",
|
||||
"nanoid": "3.3.11",
|
||||
"next": "16.3.0",
|
||||
"next": "16.3.4",
|
||||
"next-themes": "^0.2.1",
|
||||
"nextjs-toploader": "^3.9.17",
|
||||
"node-os-utils": "2.0.1",
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
sendInvoiceEmail,
|
||||
sendPaymentFailedEmail,
|
||||
} from "@/server/utils/stripe-notifications";
|
||||
import { sendTrialExpiringEmail } from "@/server/utils/trial-notifications";
|
||||
|
||||
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET!;
|
||||
|
||||
@@ -72,6 +73,7 @@ export default async function handler(
|
||||
"invoice.payment_failed",
|
||||
"customer.deleted",
|
||||
"checkout.session.completed",
|
||||
"customer.subscription.trial_will_end",
|
||||
];
|
||||
|
||||
if (!webhooksAllowed.includes(event.type)) {
|
||||
@@ -110,6 +112,12 @@ export default async function handler(
|
||||
await updateServersBasedOnQuantity(admin.id, newServersQuantity);
|
||||
break;
|
||||
}
|
||||
case "customer.subscription.trial_will_end": {
|
||||
const trialingSubscription = event.data.object as Stripe.Subscription;
|
||||
|
||||
await sendTrialExpiringEmail(stripe, trialingSubscription, event.created);
|
||||
break;
|
||||
}
|
||||
case "customer.subscription.created": {
|
||||
const newSubscription = event.data.object as Stripe.Subscription;
|
||||
|
||||
@@ -176,7 +184,10 @@ export default async function handler(
|
||||
break;
|
||||
}
|
||||
|
||||
if (newSubscription.status === "active") {
|
||||
if (
|
||||
newSubscription.status === "active" ||
|
||||
newSubscription.status === "trialing"
|
||||
) {
|
||||
const serversQuantity = getSubscriptionServersQuantity(
|
||||
newSubscription?.items?.data ?? [],
|
||||
);
|
||||
@@ -209,9 +220,12 @@ export default async function handler(
|
||||
case "invoice.payment_succeeded": {
|
||||
const newInvoice = event.data.object as Stripe.Invoice;
|
||||
|
||||
const subscription = await stripe.subscriptions.retrieve(
|
||||
newInvoice.subscription as string,
|
||||
);
|
||||
const subscriptionId = getInvoiceSubscriptionId(newInvoice);
|
||||
if (!subscriptionId) {
|
||||
break;
|
||||
}
|
||||
|
||||
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
|
||||
|
||||
if (subscription.status !== "active") {
|
||||
console.log(
|
||||
@@ -220,6 +234,14 @@ export default async function handler(
|
||||
break;
|
||||
}
|
||||
|
||||
const admin = await findUserByStripeCustomerId(
|
||||
subscription.customer as string,
|
||||
);
|
||||
|
||||
if (!admin) {
|
||||
return res.status(400).send("Webhook Error: Admin not found");
|
||||
}
|
||||
|
||||
const serversQuantity = getSubscriptionServersQuantity(
|
||||
subscription?.items?.data ?? [],
|
||||
);
|
||||
@@ -233,18 +255,10 @@ export default async function handler(
|
||||
),
|
||||
);
|
||||
|
||||
const admin = await findUserByStripeCustomerId(
|
||||
subscription.customer as string,
|
||||
);
|
||||
|
||||
if (!admin) {
|
||||
return res.status(400).send("Webhook Error: Admin not found");
|
||||
}
|
||||
if (admin.isEnterpriseCloud) {
|
||||
break;
|
||||
}
|
||||
const newServersQuantity = admin.serversQuantity;
|
||||
await updateServersBasedOnQuantity(admin.id, newServersQuantity);
|
||||
await updateServersBasedOnQuantity(admin.id, serversQuantity);
|
||||
|
||||
if (admin.sendInvoiceNotifications) {
|
||||
await sendInvoiceEmail(newInvoice, admin);
|
||||
@@ -255,9 +269,12 @@ export default async function handler(
|
||||
case "invoice.payment_failed": {
|
||||
const newInvoice = event.data.object as Stripe.Invoice;
|
||||
|
||||
const subscription = await stripe.subscriptions.retrieve(
|
||||
newInvoice.subscription as string,
|
||||
);
|
||||
const subscriptionId = getInvoiceSubscriptionId(newInvoice);
|
||||
if (!subscriptionId) {
|
||||
break;
|
||||
}
|
||||
|
||||
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
|
||||
if (subscription.status !== "active") {
|
||||
const admin = await findUserByStripeCustomerId(
|
||||
newInvoice.customer as string,
|
||||
@@ -351,6 +368,12 @@ const findUserByStripeCustomerId = async (stripeCustomerId: string) => {
|
||||
return userResult;
|
||||
};
|
||||
|
||||
const getInvoiceSubscriptionId = (invoice: Stripe.Invoice): string | null => {
|
||||
const subscription = invoice.subscription;
|
||||
if (typeof subscription === "string") return subscription;
|
||||
return subscription?.id ?? null;
|
||||
};
|
||||
|
||||
const activateServer = async (serverId: string) => {
|
||||
await db
|
||||
.update(server)
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
getCurrentPlan as getCurrentPlanForOrganization,
|
||||
getStripeClient,
|
||||
TRIAL_DURATION_DAYS,
|
||||
TRIAL_SERVER_LIMIT,
|
||||
TRIAL_SERVER_LIMITS,
|
||||
} from "@/server/utils/billing";
|
||||
import {
|
||||
type BillingTier,
|
||||
@@ -45,72 +45,82 @@ export const stripeRouter = createTRPCRouter({
|
||||
return getBillingStatus(ctx.user.ownerId);
|
||||
}),
|
||||
|
||||
startFreeTrial: adminProcedure.mutation(async ({ ctx }) => {
|
||||
if (!IS_CLOUD) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "This feature is only available in Dokploy Cloud",
|
||||
});
|
||||
}
|
||||
|
||||
if (!HOBBY_PRICE_MONTHLY_ID) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: "Trials are not configured",
|
||||
});
|
||||
}
|
||||
|
||||
const owner = await findUserById(ctx.user.ownerId);
|
||||
const billingStatus = await getBillingStatus(owner.id);
|
||||
|
||||
if (billingStatus.hasActiveAccess) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "You already have an active plan or trial",
|
||||
});
|
||||
}
|
||||
|
||||
if (billingStatus.hasUsedTrial) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "You have already used your free trial",
|
||||
});
|
||||
}
|
||||
|
||||
const stripe = getStripeClient();
|
||||
|
||||
let stripeCustomerId = owner.stripeCustomerId;
|
||||
if (stripeCustomerId) {
|
||||
const customer = await stripe.customers.retrieve(stripeCustomerId);
|
||||
if (customer.deleted) {
|
||||
stripeCustomerId = null;
|
||||
startFreeTrial: adminProcedure
|
||||
.input(z.object({ tier: z.enum(["hobby", "startup"]) }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
if (!IS_CLOUD) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "This feature is only available in Dokploy Cloud",
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!stripeCustomerId) {
|
||||
const customer = await stripe.customers.create({ email: owner.email });
|
||||
stripeCustomerId = customer.id;
|
||||
}
|
||||
|
||||
const subscription = await stripe.subscriptions.create({
|
||||
customer: stripeCustomerId,
|
||||
items: [{ price: HOBBY_PRICE_MONTHLY_ID, quantity: 1 }],
|
||||
trial_period_days: TRIAL_DURATION_DAYS,
|
||||
trial_settings: { end_behavior: { missing_payment_method: "cancel" } },
|
||||
metadata: { source: "onboarding_trial", adminId: owner.id },
|
||||
});
|
||||
const trialPriceId =
|
||||
input.tier === "startup"
|
||||
? STARTUP_BASE_PRICE_MONTHLY_ID
|
||||
: HOBBY_PRICE_MONTHLY_ID;
|
||||
if (!trialPriceId) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: "Trials are not configured",
|
||||
});
|
||||
}
|
||||
|
||||
await updateUser(owner.id, {
|
||||
stripeCustomerId,
|
||||
stripeSubscriptionId: subscription.id,
|
||||
serversQuantity: TRIAL_SERVER_LIMIT,
|
||||
});
|
||||
const owner = await findUserById(ctx.user.ownerId);
|
||||
const billingStatus = await getBillingStatus(owner.id);
|
||||
|
||||
return {
|
||||
trialEndsAt: subscription.trial_end
|
||||
? new Date(subscription.trial_end * 1000)
|
||||
: null,
|
||||
};
|
||||
}),
|
||||
if (billingStatus.hasActiveAccess) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "You already have an active plan or trial",
|
||||
});
|
||||
}
|
||||
|
||||
if (billingStatus.hasUsedTrial) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "You have already used your free trial",
|
||||
});
|
||||
}
|
||||
|
||||
const stripe = getStripeClient();
|
||||
|
||||
let stripeCustomerId = owner.stripeCustomerId;
|
||||
if (stripeCustomerId) {
|
||||
const customer = await stripe.customers.retrieve(stripeCustomerId);
|
||||
if (customer.deleted) {
|
||||
stripeCustomerId = null;
|
||||
}
|
||||
}
|
||||
if (!stripeCustomerId) {
|
||||
const customer = await stripe.customers.create({ email: owner.email });
|
||||
stripeCustomerId = customer.id;
|
||||
}
|
||||
|
||||
const subscription = await stripe.subscriptions.create({
|
||||
customer: stripeCustomerId,
|
||||
items: [{ price: trialPriceId, quantity: 1 }],
|
||||
trial_period_days: TRIAL_DURATION_DAYS,
|
||||
trial_settings: { end_behavior: { missing_payment_method: "cancel" } },
|
||||
metadata: {
|
||||
source: "onboarding_trial",
|
||||
adminId: owner.id,
|
||||
tier: input.tier,
|
||||
},
|
||||
});
|
||||
|
||||
await updateUser(owner.id, {
|
||||
stripeCustomerId,
|
||||
stripeSubscriptionId: subscription.id,
|
||||
serversQuantity: TRIAL_SERVER_LIMITS[input.tier],
|
||||
});
|
||||
|
||||
return {
|
||||
trialEndsAt: subscription.trial_end
|
||||
? new Date(subscription.trial_end * 1000)
|
||||
: null,
|
||||
};
|
||||
}),
|
||||
|
||||
getProducts: adminProcedure.query(async ({ ctx }) => {
|
||||
const user = await findUserById(ctx.user.ownerId);
|
||||
@@ -343,9 +353,15 @@ export const stripeRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const isTrialing = subscription.status === "trialing";
|
||||
// Trials are capped at the plan's included servers; paid plans can scale.
|
||||
const serverQuantity = isTrialing
|
||||
? TRIAL_SERVER_LIMITS[input.tier]
|
||||
: input.serverQuantity;
|
||||
|
||||
const newItems = getStripeItems(
|
||||
input.tier as BillingTier,
|
||||
input.serverQuantity,
|
||||
serverQuantity,
|
||||
input.isAnnual,
|
||||
);
|
||||
const currentItems = subscription.items.data;
|
||||
@@ -371,7 +387,7 @@ export const stripeRouter = createTRPCRouter({
|
||||
|
||||
await stripe.subscriptions.update(owner.stripeSubscriptionId, {
|
||||
items: updateItems,
|
||||
proration_behavior: "create_prorations",
|
||||
proration_behavior: isTrialing ? "none" : "create_prorations",
|
||||
});
|
||||
|
||||
return { ok: true };
|
||||
|
||||
@@ -16,7 +16,7 @@ export const getStripeClient = () =>
|
||||
apiVersion: "2024-09-30.acacia",
|
||||
});
|
||||
|
||||
const planFromPriceIds = (priceIds: string[]): BillingPlan | null => {
|
||||
export const planFromPriceIds = (priceIds: string[]): BillingPlan | null => {
|
||||
if (
|
||||
priceIds.some(
|
||||
(id) =>
|
||||
@@ -78,7 +78,11 @@ export const getCurrentPlan = async (
|
||||
};
|
||||
|
||||
export const TRIAL_DURATION_DAYS = 7;
|
||||
export const TRIAL_SERVER_LIMIT = 1;
|
||||
export type TrialTier = "hobby" | "startup";
|
||||
export const TRIAL_SERVER_LIMITS: Record<TrialTier, number> = {
|
||||
hobby: 1,
|
||||
startup: 3,
|
||||
};
|
||||
|
||||
export interface BillingStatus {
|
||||
plan: BillingPlan | null;
|
||||
@@ -87,6 +91,7 @@ export interface BillingStatus {
|
||||
trialDaysRemaining: number | null;
|
||||
hasUsedTrial: boolean;
|
||||
hasActiveAccess: boolean;
|
||||
hasPaymentMethod: boolean;
|
||||
}
|
||||
|
||||
export const getBillingStatus = async (
|
||||
@@ -100,6 +105,7 @@ export const getBillingStatus = async (
|
||||
trialDaysRemaining: null,
|
||||
hasUsedTrial: false,
|
||||
hasActiveAccess: true,
|
||||
hasPaymentMethod: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -112,6 +118,7 @@ export const getBillingStatus = async (
|
||||
trialDaysRemaining: null,
|
||||
hasUsedTrial: false,
|
||||
hasActiveAccess: false,
|
||||
hasPaymentMethod: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,7 +126,7 @@ export const getBillingStatus = async (
|
||||
const subscriptions = await stripe.subscriptions.list({
|
||||
customer: owner.stripeCustomerId,
|
||||
status: "all",
|
||||
expand: ["data.items.data.price"],
|
||||
expand: ["data.items.data.price", "data.customer"],
|
||||
});
|
||||
|
||||
const relevantSubs = subscriptions.data.filter(
|
||||
@@ -133,6 +140,12 @@ export const getBillingStatus = async (
|
||||
const trialingSub = subscriptions.data.find(
|
||||
(sub) => sub.status === "trialing",
|
||||
);
|
||||
|
||||
const currentSub = trialingSub ?? relevantSubs[0];
|
||||
const customer = currentSub?.customer as Stripe.Customer | undefined;
|
||||
const hasPaymentMethod =
|
||||
!!currentSub?.default_payment_method ||
|
||||
!!customer?.invoice_settings?.default_payment_method;
|
||||
const trialEndsAt = trialingSub?.trial_end
|
||||
? new Date(trialingSub.trial_end * 1000)
|
||||
: null;
|
||||
@@ -148,6 +161,7 @@ export const getBillingStatus = async (
|
||||
isOnTrial: !!trialingSub,
|
||||
trialEndsAt,
|
||||
trialDaysRemaining,
|
||||
hasPaymentMethod,
|
||||
hasUsedTrial: subscriptions.data.length > 0,
|
||||
hasActiveAccess: plan !== null || !!trialingSub,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { db } from "@dokploy/server/db";
|
||||
import TrialExpiringEmail from "@dokploy/server/emails/emails/trial-expiring";
|
||||
import { sendEmail } from "@dokploy/server/verification/send-verification-email";
|
||||
import { render } from "@react-email/components";
|
||||
import { format } from "date-fns";
|
||||
import { eq } from "drizzle-orm";
|
||||
import type Stripe from "stripe";
|
||||
import { user } from "@/server/db/schema";
|
||||
import { planFromPriceIds } from "@/server/utils/billing";
|
||||
import { WEBSITE_URL } from "@/server/utils/stripe";
|
||||
|
||||
const PLAN_LABELS: Record<string, string> = {
|
||||
hobby: "Hobby",
|
||||
startup: "Startup",
|
||||
legacy: "Legacy",
|
||||
};
|
||||
|
||||
const customerIdOf = (subscription: Stripe.Subscription) =>
|
||||
typeof subscription.customer === "string"
|
||||
? subscription.customer
|
||||
: subscription.customer.id;
|
||||
|
||||
const hasPaymentMethod = async (
|
||||
stripe: Stripe,
|
||||
subscription: Stripe.Subscription,
|
||||
) => {
|
||||
if (subscription.default_payment_method) return true;
|
||||
|
||||
const customer = await stripe.customers.retrieve(customerIdOf(subscription));
|
||||
if (customer.deleted) return true;
|
||||
return !!customer.invoice_settings?.default_payment_method;
|
||||
};
|
||||
|
||||
export const sendTrialExpiringEmail = async (
|
||||
stripe: Stripe,
|
||||
subscription: Stripe.Subscription,
|
||||
// Stripe retries a failing webhook for days, so the countdown is measured
|
||||
// from when Stripe emitted the event rather than from the current time.
|
||||
notifiedAtSeconds: number,
|
||||
) => {
|
||||
if (!subscription.trial_end) return false;
|
||||
if (await hasPaymentMethod(stripe, subscription)) return false;
|
||||
|
||||
const owner = await db.query.user.findFirst({
|
||||
where: eq(user.stripeCustomerId, customerIdOf(subscription)),
|
||||
});
|
||||
if (!owner || owner.isEnterpriseCloud) return false;
|
||||
|
||||
const trialEndsAt = new Date(subscription.trial_end * 1000);
|
||||
const daysRemaining = Math.max(
|
||||
1,
|
||||
Math.ceil((subscription.trial_end - notifiedAtSeconds) / (60 * 60 * 24)),
|
||||
);
|
||||
const plan = planFromPriceIds(
|
||||
subscription.items.data.map((item) => (item.price as Stripe.Price).id),
|
||||
);
|
||||
|
||||
const htmlContent = await render(
|
||||
TrialExpiringEmail({
|
||||
userName: owner.firstName || "User",
|
||||
planName: plan ? (PLAN_LABELS[plan] ?? plan) : "Trial",
|
||||
daysRemaining,
|
||||
endsOn: format(trialEndsAt, "MMM dd, yyyy"),
|
||||
billingUrl: `${WEBSITE_URL}/dashboard/settings/billing`,
|
||||
}),
|
||||
);
|
||||
|
||||
await sendEmail({
|
||||
email: owner.email,
|
||||
subject:
|
||||
daysRemaining === 1
|
||||
? "Your Dokploy trial ends tomorrow"
|
||||
: `Your Dokploy trial ends in ${daysRemaining} days`,
|
||||
text: htmlContent,
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
@@ -0,0 +1,141 @@
|
||||
import {
|
||||
Body,
|
||||
Button,
|
||||
Column,
|
||||
Container,
|
||||
Head,
|
||||
Heading,
|
||||
Hr,
|
||||
Html,
|
||||
Img,
|
||||
Link,
|
||||
Preview,
|
||||
Row,
|
||||
Section,
|
||||
Tailwind,
|
||||
Text,
|
||||
} from "@react-email/components";
|
||||
import { emailTailwindConfig } from "../tailwind-config";
|
||||
|
||||
export type TemplateProps = {
|
||||
userName: string;
|
||||
planName: string;
|
||||
daysRemaining: number;
|
||||
endsOn: string;
|
||||
billingUrl: string;
|
||||
};
|
||||
|
||||
export const TrialExpiringEmail = ({
|
||||
userName = "User",
|
||||
planName = "Hobby",
|
||||
daysRemaining = 3,
|
||||
endsOn = "2024-01-01",
|
||||
billingUrl = "https://app.dokploy.com/dashboard/settings/billing",
|
||||
}: TemplateProps) => {
|
||||
const dayLabel = daysRemaining === 1 ? "day" : "days";
|
||||
const previewText =
|
||||
daysRemaining === 1
|
||||
? "Your Dokploy trial ends tomorrow"
|
||||
: `Your Dokploy trial ends in ${daysRemaining} ${dayLabel}`;
|
||||
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<Preview>{previewText}</Preview>
|
||||
<Tailwind config={emailTailwindConfig}>
|
||||
<Body className="bg-[#f4f4f5] my-auto mx-auto font-sans">
|
||||
<Container className="my-[40px] mx-auto max-w-[520px]">
|
||||
<Section className="bg-[#09090b] rounded-t-xl px-[40px] py-[32px] text-center">
|
||||
<Img
|
||||
src="https://raw.githubusercontent.com/Dokploy/website/refs/heads/main/apps/docs/public/logo-dokploy-blackpng.png"
|
||||
width="190"
|
||||
height="120"
|
||||
alt="Dokploy"
|
||||
className="my-0 mx-auto"
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section className="bg-white px-[40px] py-[32px]">
|
||||
<Heading className="text-[#09090b] text-[22px] font-semibold m-0 mb-[8px]">
|
||||
{daysRemaining === 1
|
||||
? "Your trial ends tomorrow"
|
||||
: `Your trial ends in ${daysRemaining} ${dayLabel}`}
|
||||
</Heading>
|
||||
<Text className="text-[#71717a] text-[14px] leading-[22px] m-0 mb-[24px]">
|
||||
Hello {userName}, add a payment method to keep your servers and
|
||||
applications running once the trial ends.
|
||||
</Text>
|
||||
|
||||
<Section className="border border-solid border-[#e4e4e7] rounded-lg overflow-hidden mb-[24px]">
|
||||
<Row className="bg-[#fafafa]">
|
||||
<Column className="px-[20px] py-[14px] w-[50%]">
|
||||
<Text className="text-[#71717a] text-[12px] font-medium uppercase tracking-wider m-0">
|
||||
Plan
|
||||
</Text>
|
||||
<Text className="text-[#09090b] text-[14px] font-semibold m-0 mt-[4px]">
|
||||
{planName}
|
||||
</Text>
|
||||
</Column>
|
||||
<Column className="px-[20px] py-[14px] w-[50%]">
|
||||
<Text className="text-[#71717a] text-[12px] font-medium uppercase tracking-wider m-0">
|
||||
Trial ends
|
||||
</Text>
|
||||
<Text className="text-[#09090b] text-[14px] font-semibold m-0 mt-[4px]">
|
||||
{endsOn}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
|
||||
<Section className="bg-[#fefce8] border border-solid border-[#fef08a] rounded-lg px-[20px] py-[16px] mb-[24px]">
|
||||
<Text className="text-[#854d0e] text-[13px] leading-[20px] m-0">
|
||||
Without a payment method your subscription is cancelled when
|
||||
the trial ends and your servers are deactivated.
|
||||
</Text>
|
||||
</Section>
|
||||
|
||||
<Section className="text-center mb-[24px]">
|
||||
<Button
|
||||
href={billingUrl}
|
||||
className="bg-[#09090b] rounded-lg text-white text-[14px] font-semibold no-underline text-center px-[24px] py-[12px]"
|
||||
>
|
||||
Add Payment Method
|
||||
</Button>
|
||||
</Section>
|
||||
|
||||
<Hr className="border-[#e4e4e7] my-[24px]" />
|
||||
|
||||
<Text className="text-[#a1a1aa] text-[12px] leading-[18px] m-0">
|
||||
You are billed only when the trial ends. You can cancel at any
|
||||
time before then.
|
||||
</Text>
|
||||
</Section>
|
||||
|
||||
<Section className="bg-[#fafafa] rounded-b-xl px-[40px] py-[24px] text-center border-t border-solid border-[#e4e4e7]">
|
||||
<Text className="text-[#a1a1aa] text-[12px] leading-[18px] m-0">
|
||||
This is an automated email from{" "}
|
||||
<Link
|
||||
href="https://dokploy.com"
|
||||
className="text-[#71717a] underline"
|
||||
>
|
||||
Dokploy Cloud
|
||||
</Link>
|
||||
. If you have any questions about your billing, please contact
|
||||
our{" "}
|
||||
<Link
|
||||
href="https://discord.gg/2tBnJ3jDJc"
|
||||
className="text-[#71717a] underline"
|
||||
>
|
||||
support team
|
||||
</Link>
|
||||
.
|
||||
</Text>
|
||||
</Section>
|
||||
</Container>
|
||||
</Body>
|
||||
</Tailwind>
|
||||
</Html>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrialExpiringEmail;
|
||||
@@ -497,6 +497,7 @@ export interface ComposeSpecification {
|
||||
*/
|
||||
include?: DefinitionsInclude[];
|
||||
services?: PropertiesServices;
|
||||
models?: PropertiesModels;
|
||||
networks?: PropertiesNetworks;
|
||||
volumes?: PropertiesVolumes;
|
||||
secrets?: PropertiesSecrets;
|
||||
@@ -648,6 +649,15 @@ export interface DefinitionsService {
|
||||
mem_swappiness?: number;
|
||||
memswap_limit?: number | string;
|
||||
network_mode?: string;
|
||||
models?:
|
||||
| ListOfStrings
|
||||
| {
|
||||
[k: string]: {
|
||||
endpoint_var?: string;
|
||||
model_var?: string;
|
||||
[key: `x-${string}`]: unknown;
|
||||
} | null;
|
||||
};
|
||||
networks?:
|
||||
| ListOfStrings
|
||||
| {
|
||||
@@ -877,3 +887,13 @@ export interface DefinitionsConfig {
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface PropertiesModels {
|
||||
[k: string]: DefinitionsModel;
|
||||
}
|
||||
export interface DefinitionsModel {
|
||||
name?: string;
|
||||
model: string;
|
||||
context_size?: number;
|
||||
runtime_flags?: string[];
|
||||
[key: `x-${string}`]: unknown;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ export const sendDatabaseBackupNotifications = async ({
|
||||
`🛠Project: ${projectName}\n` +
|
||||
`⚙️Application: ${applicationName}\n` +
|
||||
`❔Type: ${databaseType}\n` +
|
||||
`📂Database Name: ${databaseName}` +
|
||||
`📂Database Name: ${databaseName}\n` +
|
||||
`🕒Date: ${date.toLocaleString()}\n` +
|
||||
`${type === "error" && errorMessage ? `❌Error:\n${errorMessage}` : ""}`,
|
||||
);
|
||||
|
||||
@@ -79,6 +79,12 @@ const readPath = async (
|
||||
// still reports success. Single secrets read via /raw/{name} expand by
|
||||
// default, which makes the difference easy to miss in the UI.
|
||||
expandSecretReferences: "true",
|
||||
// Secrets pulled in through "Import Secrets" are not part of `secrets`:
|
||||
// they come back in a separate `imports` array, and only when this is
|
||||
// asked for. Note the snake_case — `includeImports` is silently ignored
|
||||
// (the request still returns 200 with an empty `imports`), which is why
|
||||
// an imported secret looked like it simply did not exist.
|
||||
include_imports: "true",
|
||||
});
|
||||
const response = await vaultFetch(
|
||||
`${baseUrl(config)}/api/v3/secrets/raw?${params.toString()}`,
|
||||
@@ -93,9 +99,17 @@ const readPath = async (
|
||||
|
||||
const body = (await response.json()) as {
|
||||
secrets?: { secretKey: string; secretValue: string }[];
|
||||
imports?: { secrets?: { secretKey: string; secretValue: string }[] }[];
|
||||
};
|
||||
|
||||
const secrets: Record<string, string> = {};
|
||||
// Imported first, then the folder's own: Infisical resolves a name defined
|
||||
// in both in favour of the local one, so writing local last preserves that.
|
||||
for (const imported of body.imports ?? []) {
|
||||
for (const secret of imported.secrets ?? []) {
|
||||
secrets[secret.secretKey] = secret.secretValue;
|
||||
}
|
||||
}
|
||||
for (const secret of body.secrets ?? []) {
|
||||
secrets[secret.secretKey] = secret.secretValue;
|
||||
}
|
||||
|
||||
Generated
+243
-243
@@ -55,7 +55,7 @@ importers:
|
||||
version: 4.12.2
|
||||
inngest:
|
||||
specifier: 3.40.1
|
||||
version: 3.40.1(encoding@0.1.13)(express@5.2.1)(h3@1.15.1)(hono@4.12.2)(next@16.3.0(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@7.0.2)
|
||||
version: 3.40.1(encoding@0.1.13)(express@5.2.1)(h3@1.15.1)(hono@4.12.2)(next@16.3.4(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@7.0.2)
|
||||
pino:
|
||||
specifier: 9.4.0
|
||||
version: 9.4.0
|
||||
@@ -131,16 +131,16 @@ importers:
|
||||
version: 3.1108.0
|
||||
'@better-auth/api-key':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))
|
||||
'@better-auth/passkey':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)
|
||||
'@better-auth/scim':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))
|
||||
'@better-auth/sso':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))
|
||||
'@codemirror/autocomplete':
|
||||
specifier: ^6.18.6
|
||||
version: 6.20.3
|
||||
@@ -185,7 +185,7 @@ importers:
|
||||
version: 13.9.1
|
||||
'@openpanel/nextjs':
|
||||
specifier: ^1.5.1
|
||||
version: 1.5.1(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
version: 1.5.1(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
'@react-email/components':
|
||||
specifier: ^1.0.12
|
||||
version: 1.0.12(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
@@ -209,7 +209,7 @@ importers:
|
||||
version: 11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2)
|
||||
'@trpc/next':
|
||||
specifier: ^11.10.0
|
||||
version: 11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(react@19.2.7)(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)
|
||||
version: 11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(react@19.2.7)(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)
|
||||
'@trpc/react-query':
|
||||
specifier: ^11.10.0
|
||||
version: 11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(react@19.2.7)(typescript@7.0.2)
|
||||
@@ -245,7 +245,7 @@ importers:
|
||||
version: 5.1.1(encoding@0.1.13)
|
||||
better-auth:
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(165e0d14ffc9aaf8b4cab70e414c9093)
|
||||
version: 1.6.23(9540743d27d6a8e6f2915ad16dc18aab)
|
||||
bl:
|
||||
specifier: 6.0.11
|
||||
version: 6.0.11
|
||||
@@ -304,14 +304,14 @@ importers:
|
||||
specifier: 3.3.11
|
||||
version: 3.3.11
|
||||
next:
|
||||
specifier: 16.3.0
|
||||
version: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
specifier: 16.3.4
|
||||
version: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
next-themes:
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
version: 0.2.1(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
nextjs-toploader:
|
||||
specifier: ^3.9.17
|
||||
version: 3.9.17(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
version: 3.9.17(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
node-os-utils:
|
||||
specifier: 2.0.1
|
||||
version: 2.0.1
|
||||
@@ -613,16 +613,16 @@ importers:
|
||||
version: 3.1108.0
|
||||
'@better-auth/api-key':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))
|
||||
'@better-auth/passkey':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)
|
||||
'@better-auth/scim':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))
|
||||
'@better-auth/sso':
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))
|
||||
version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))
|
||||
'@better-auth/utils':
|
||||
specifier: 0.4.2
|
||||
version: 0.4.2
|
||||
@@ -661,7 +661,7 @@ importers:
|
||||
version: 5.1.1(encoding@0.1.13)
|
||||
better-auth:
|
||||
specifier: 1.6.23
|
||||
version: 1.6.23(e687b32eb00a1602e570e2163c94e965)
|
||||
version: 1.6.23(1f696af711ca01112337d810adfad25c)
|
||||
bl:
|
||||
specifier: 6.0.11
|
||||
version: 6.0.11
|
||||
@@ -1638,144 +1638,144 @@ packages:
|
||||
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@img/sharp-darwin-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==}
|
||||
'@img/sharp-darwin-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-darwin-x64@0.35.3':
|
||||
resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==}
|
||||
'@img/sharp-darwin-x64@0.35.4':
|
||||
resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-freebsd-wasm32@0.35.3':
|
||||
resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==}
|
||||
'@img/sharp-freebsd-wasm32@0.35.4':
|
||||
resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
os: [freebsd]
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.2':
|
||||
resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==}
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.3':
|
||||
resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.3.2':
|
||||
resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==}
|
||||
'@img/sharp-libvips-darwin-x64@1.3.3':
|
||||
resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.3.2':
|
||||
resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==}
|
||||
'@img/sharp-libvips-linux-arm64@1.3.3':
|
||||
resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.3.2':
|
||||
resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==}
|
||||
'@img/sharp-libvips-linux-arm@1.3.3':
|
||||
resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.2':
|
||||
resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==}
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.3':
|
||||
resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.2':
|
||||
resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==}
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.3':
|
||||
resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.3.2':
|
||||
resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==}
|
||||
'@img/sharp-libvips-linux-s390x@1.3.3':
|
||||
resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.3.2':
|
||||
resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==}
|
||||
'@img/sharp-libvips-linux-x64@1.3.3':
|
||||
resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.2':
|
||||
resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==}
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.3':
|
||||
resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.2':
|
||||
resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==}
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.3':
|
||||
resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linux-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==}
|
||||
'@img/sharp-linux-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linux-arm@0.35.3':
|
||||
resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==}
|
||||
'@img/sharp-linux-arm@0.35.4':
|
||||
resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linux-ppc64@0.35.3':
|
||||
resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==}
|
||||
'@img/sharp-linux-ppc64@0.35.4':
|
||||
resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linux-riscv64@0.35.3':
|
||||
resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==}
|
||||
'@img/sharp-linux-riscv64@0.35.4':
|
||||
resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linux-s390x@0.35.3':
|
||||
resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==}
|
||||
'@img/sharp-linux-s390x@0.35.4':
|
||||
resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linux-x64@0.35.3':
|
||||
resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==}
|
||||
'@img/sharp-linux-x64@0.35.4':
|
||||
resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==}
|
||||
'@img/sharp-linuxmusl-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.35.3':
|
||||
resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==}
|
||||
'@img/sharp-linuxmusl-x64@0.35.4':
|
||||
resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@img/sharp-wasm32@0.35.3':
|
||||
resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==}
|
||||
'@img/sharp-wasm32@0.35.4':
|
||||
resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
|
||||
'@img/sharp-webcontainers-wasm32@0.35.3':
|
||||
resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==}
|
||||
'@img/sharp-webcontainers-wasm32@0.35.4':
|
||||
resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@img/sharp-win32-arm64@0.35.3':
|
||||
resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==}
|
||||
'@img/sharp-win32-arm64@0.35.4':
|
||||
resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@img/sharp-win32-ia32@0.35.3':
|
||||
resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==}
|
||||
'@img/sharp-win32-ia32@0.35.4':
|
||||
resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==}
|
||||
engines: {node: ^20.9.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@img/sharp-win32-x64@0.35.3':
|
||||
resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==}
|
||||
'@img/sharp-win32-x64@0.35.4':
|
||||
resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -2013,53 +2013,53 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@next/env@16.3.0':
|
||||
resolution: {integrity: sha512-o9r1S0BNiNreHP9Vs+Qnqd9kviDkJh8xIACY7UFZSmiGbbQRzPBBosvHzAU4TULHOIuOj/18RSsyz2qrREmIFw==}
|
||||
'@next/env@16.3.4':
|
||||
resolution: {integrity: sha512-cjWZnUUa6jZq2kFaNe/ZyJdZonOZ/QoN0Zka2nz/FLOrfx14pQuM9c5RaSVkWMqgdt4ksgPAMWPyHSs/CyV48Q==}
|
||||
|
||||
'@next/swc-darwin-arm64@16.3.0':
|
||||
resolution: {integrity: sha512-55hpqq18bEVAlxedlTt3tFqZmKg2nUXT1kn1G/BGEy0R13h3LwtwHPVzzjG6P4LLeOHE32PFDQUVaJEWvBEZBw==}
|
||||
'@next/swc-darwin-arm64@16.3.4':
|
||||
resolution: {integrity: sha512-iBr3I5LZNk5/bgl5//iTgD2tcym14MX0Xo7fD//u9dYAEgGzza1y9oywluPtf74YnOswVdH1908aK9xVz7zQTw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-darwin-x64@16.3.0':
|
||||
resolution: {integrity: sha512-SOi96kSaF5T+0wW4koiM1bWzSPwjzTesC1p3df+FjdOi5LIQkBK/blxh7HdoKnNuI4PURF1OO7TZqtfnbWDSgw==}
|
||||
'@next/swc-darwin-x64@16.3.4':
|
||||
resolution: {integrity: sha512-2dpiSyl2Jw/NrBPaU2MAKGSa+2MR82pJIn4Sm5Rjr+gxAeuh0z158Su3Z2O8zn7UNNq+ej4bToed6RcRN/Lydg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-linux-arm64-gnu@16.3.0':
|
||||
resolution: {integrity: sha512-P0gZAoPMF4dyTRzhmkV4PrqVzSOB6t4mC1oI3c4dqijJ+OVEVx5clIXAKR4/uQpsqw2KKM/0D5tVumcR2r5blg==}
|
||||
'@next/swc-linux-arm64-gnu@16.3.4':
|
||||
resolution: {integrity: sha512-+t+U8HZT+fApePCS5h89CSH3datz29MkzyfCn+6fpsZBG/oiEOhINcb9rtkv6sdpToLGFn2e6146NzaKCXkqrA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-arm64-musl@16.3.0':
|
||||
resolution: {integrity: sha512-tXXGKJw0m37O0eKJARVTX/TheKPhz0QFVtVVZXmOig+9YKLQOSP6hvf2pxv5DO7CLEJyTHx3Pg043CDQkv1G4Q==}
|
||||
'@next/swc-linux-arm64-musl@16.3.4':
|
||||
resolution: {integrity: sha512-mx03GNs1ocQA5JQ4FxDMmIsNkdrZh8cuezKCrId28e5/gIPU/l7Kcy2+vmCCzdjnnmXJy+iOAu+7K0QppO6Urg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-x64-gnu@16.3.0':
|
||||
resolution: {integrity: sha512-pjGxK5EY7yWml78ALejFkWmgHsU7wbFQrISiugpH6FbUJhgEvw3xFZ/EBAtLl7QtL0WdQKiG9eWJ3mOKGTukHw==}
|
||||
'@next/swc-linux-x64-gnu@16.3.4':
|
||||
resolution: {integrity: sha512-YIhGY6fSMfha52bnVxnzc9zaVBzJg+cqQTOD8tXIBSx4fuv0pVMxQTE0PaS59YhnMOiYiG09IMwxJAf/CFm/Dw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-x64-musl@16.3.0':
|
||||
resolution: {integrity: sha512-sjo++Xx+lomlPs3HRsHWhVDyGG6ms1kGW5EtHLERdII8AyG1i+f6aq68xHREO6AEMlhjTNEWBSmfJfqm9orf7g==}
|
||||
'@next/swc-linux-x64-musl@16.3.4':
|
||||
resolution: {integrity: sha512-+eaaX6axpDb0yF1GCpiERe6njplvdC+nks/fKfcHu3XPGRrald8P3/X7yv7QLdjA51knnxwl9pxdIJsg+w1L+Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-win32-arm64-msvc@16.3.0':
|
||||
resolution: {integrity: sha512-C5JSgiO54wURdaxdEUIXqkz04uMqC9UmPX1gtDrV/5Tf1UowdWYI8uA5hfFbPolTlp0q4KZ60xlHePNibf0VIw==}
|
||||
'@next/swc-win32-arm64-msvc@16.3.4':
|
||||
resolution: {integrity: sha512-0jcXW7Xs/uzICrmgV3MhDYDeRy++1CqnpDIerlPIqYO4bhzB4WNbX/aRnQclustsAyTkFKB0z6rbcjmNg5tR8A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@next/swc-win32-x64-msvc@16.3.0':
|
||||
resolution: {integrity: sha512-fDOggsweNb5SSw0ZKVk6U+gxSyGFFlIBY/LBc1r8GUj4u/6t6oArL+Pmkg0MBnsgR+KkdsURilVH4F3GXUGepA==}
|
||||
'@next/swc-win32-x64-msvc@16.3.4':
|
||||
resolution: {integrity: sha512-vvBzwu1pYQCp92maZCFCIw/XgOTMR5tur9GjakwIo2cmwRTMKajRZZDS9+e4KsUZWKu1E007WUeAFXRRjZeuzw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -4181,8 +4181,8 @@ packages:
|
||||
resolution: {integrity: sha512-qMx1nOrzoB+PF+pzb26Q4Tc2sOlrx9Ba2UBNX9hB31Omrq+QoZ2Gly0KLrQWw4Of1AQ4J9lnD+XOdwOdcdXqqw==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
|
||||
'@swc/helpers@0.5.15':
|
||||
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
|
||||
'@swc/helpers@0.5.23':
|
||||
resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==}
|
||||
|
||||
'@szmarczak/http-timer@5.0.1':
|
||||
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
|
||||
@@ -7315,8 +7315,8 @@ packages:
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
|
||||
next@16.3.0:
|
||||
resolution: {integrity: sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A==}
|
||||
next@16.3.4:
|
||||
resolution: {integrity: sha512-/Ztf6CeRH+ejEXUrYtqI4gkS66eFIHuSwqi60RgcpWKodxFZx2/dqVCMKBwILfAHXQ+F1b1vAudgj3mnxqtoIA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -8367,8 +8367,8 @@ packages:
|
||||
resolution: {integrity: sha512-UV0cchFea9hO7poV1CuEP0wvmYjpAqcxCKdy23bndl2Du2ARtDs8A4xdzfhUjDBeOW1nNpJ6lXmsEpsply2SfQ==}
|
||||
hasBin: true
|
||||
|
||||
sharp@0.35.3:
|
||||
resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==}
|
||||
sharp@0.35.4:
|
||||
resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
peerDependencies:
|
||||
'@types/node': '*'
|
||||
@@ -9908,19 +9908,19 @@ snapshots:
|
||||
|
||||
'@balena/dockerignore@1.0.2': {}
|
||||
|
||||
'@better-auth/api-key@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))':
|
||||
'@better-auth/api-key@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
better-auth: 1.6.23(165e0d14ffc9aaf8b4cab70e414c9093)
|
||||
better-auth: 1.6.23(1f696af711ca01112337d810adfad25c)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@better-auth/api-key@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))':
|
||||
'@better-auth/api-key@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
better-auth: 1.6.23(e687b32eb00a1602e570e2163c94e965)
|
||||
better-auth: 1.6.23(9540743d27d6a8e6f2915ad16dc18aab)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
@@ -9964,26 +9964,26 @@ snapshots:
|
||||
optionalDependencies:
|
||||
mongodb: 7.1.0(socks@2.8.8)
|
||||
|
||||
'@better-auth/passkey@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)':
|
||||
'@better-auth/passkey@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
'@better-fetch/fetch': 1.3.1
|
||||
'@simplewebauthn/browser': 13.3.0
|
||||
'@simplewebauthn/server': 13.3.2
|
||||
better-auth: 1.6.23(165e0d14ffc9aaf8b4cab70e414c9093)
|
||||
better-auth: 1.6.23(1f696af711ca01112337d810adfad25c)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
nanostores: 1.1.1
|
||||
zod: 4.3.6
|
||||
|
||||
'@better-auth/passkey@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)':
|
||||
'@better-auth/passkey@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))(nanostores@1.1.1)':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
'@better-fetch/fetch': 1.3.1
|
||||
'@simplewebauthn/browser': 13.3.0
|
||||
'@simplewebauthn/server': 13.3.2
|
||||
better-auth: 1.6.23(e687b32eb00a1602e570e2163c94e965)
|
||||
better-auth: 1.6.23(9540743d27d6a8e6f2915ad16dc18aab)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
nanostores: 1.1.1
|
||||
zod: 4.3.6
|
||||
@@ -9996,28 +9996,28 @@ snapshots:
|
||||
'@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)
|
||||
|
||||
'@better-auth/scim@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))':
|
||||
'@better-auth/scim@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
better-auth: 1.6.23(165e0d14ffc9aaf8b4cab70e414c9093)
|
||||
better-auth: 1.6.23(1f696af711ca01112337d810adfad25c)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@better-auth/scim@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))':
|
||||
'@better-auth/scim@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
better-auth: 1.6.23(e687b32eb00a1602e570e2163c94e965)
|
||||
better-auth: 1.6.23(9540743d27d6a8e6f2915ad16dc18aab)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@better-auth/sso@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093))(better-call@1.3.7(zod@4.3.6))':
|
||||
'@better-auth/sso@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(1f696af711ca01112337d810adfad25c))(better-call@1.3.7(zod@4.3.6))':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
'@better-fetch/fetch': 1.3.1
|
||||
better-auth: 1.6.23(165e0d14ffc9aaf8b4cab70e414c9093)
|
||||
better-auth: 1.6.23(1f696af711ca01112337d810adfad25c)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
fast-xml-parser: 5.9.3
|
||||
jose: 6.1.3
|
||||
@@ -10025,12 +10025,12 @@ snapshots:
|
||||
tldts: 6.1.86
|
||||
zod: 4.3.6
|
||||
|
||||
'@better-auth/sso@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965))(better-call@1.3.7(zod@4.3.6))':
|
||||
'@better-auth/sso@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab))(better-call@1.3.7(zod@4.3.6))':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
'@better-fetch/fetch': 1.3.1
|
||||
better-auth: 1.6.23(e687b32eb00a1602e570e2163c94e965)
|
||||
better-auth: 1.6.23(9540743d27d6a8e6f2915ad16dc18aab)
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
fast-xml-parser: 5.9.3
|
||||
jose: 6.1.3
|
||||
@@ -10385,108 +10385,108 @@ snapshots:
|
||||
'@img/colour@1.1.0':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-darwin-arm64@0.35.3':
|
||||
'@img/sharp-darwin-arm64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.2
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-darwin-x64@0.35.3':
|
||||
'@img/sharp-darwin-x64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.2
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-freebsd-wasm32@0.35.3':
|
||||
'@img/sharp-freebsd-wasm32@0.35.4':
|
||||
dependencies:
|
||||
'@img/sharp-wasm32': 0.35.3
|
||||
'@img/sharp-wasm32': 0.35.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.2':
|
||||
'@img/sharp-libvips-darwin-arm64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.3.2':
|
||||
'@img/sharp-libvips-darwin-x64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.3.2':
|
||||
'@img/sharp-libvips-linux-arm64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.3.2':
|
||||
'@img/sharp-libvips-linux-arm@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.2':
|
||||
'@img/sharp-libvips-linux-ppc64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.2':
|
||||
'@img/sharp-libvips-linux-riscv64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.3.2':
|
||||
'@img/sharp-libvips-linux-s390x@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.3.2':
|
||||
'@img/sharp-libvips-linux-x64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.2':
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.2':
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.3.3':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm64@0.35.3':
|
||||
'@img/sharp-linux-arm64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.2
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm@0.35.3':
|
||||
'@img/sharp-linux-arm@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm': 1.3.2
|
||||
'@img/sharp-libvips-linux-arm': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-ppc64@0.35.3':
|
||||
'@img/sharp-linux-ppc64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.2
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-riscv64@0.35.3':
|
||||
'@img/sharp-linux-riscv64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.2
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-s390x@0.35.3':
|
||||
'@img/sharp-linux-s390x@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.2
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-x64@0.35.3':
|
||||
'@img/sharp-linux-x64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-x64': 1.3.2
|
||||
'@img/sharp-libvips-linux-x64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.35.3':
|
||||
'@img/sharp-linuxmusl-arm64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.2
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.35.3':
|
||||
'@img/sharp-linuxmusl-x64@0.35.4':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.2
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-wasm32@0.35.3':
|
||||
'@img/sharp-wasm32@0.35.4':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.11.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-webcontainers-wasm32@0.35.3':
|
||||
'@img/sharp-webcontainers-wasm32@0.35.4':
|
||||
dependencies:
|
||||
'@img/sharp-wasm32': 0.35.3
|
||||
'@img/sharp-wasm32': 0.35.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-arm64@0.35.3':
|
||||
'@img/sharp-win32-arm64@0.35.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-ia32@0.35.3':
|
||||
'@img/sharp-win32-ia32@0.35.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-x64@0.35.3':
|
||||
'@img/sharp-win32-x64@0.35.4':
|
||||
optional: true
|
||||
|
||||
'@inngest/ai@0.1.7':
|
||||
@@ -10752,30 +10752,30 @@ snapshots:
|
||||
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
|
||||
optional: true
|
||||
|
||||
'@next/env@16.3.0': {}
|
||||
'@next/env@16.3.4': {}
|
||||
|
||||
'@next/swc-darwin-arm64@16.3.0':
|
||||
'@next/swc-darwin-arm64@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-darwin-x64@16.3.0':
|
||||
'@next/swc-darwin-x64@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-gnu@16.3.0':
|
||||
'@next/swc-linux-arm64-gnu@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-musl@16.3.0':
|
||||
'@next/swc-linux-arm64-musl@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-gnu@16.3.0':
|
||||
'@next/swc-linux-x64-gnu@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-musl@16.3.0':
|
||||
'@next/swc-linux-x64-musl@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-arm64-msvc@16.3.0':
|
||||
'@next/swc-win32-arm64-msvc@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-x64-msvc@16.3.0':
|
||||
'@next/swc-win32-x64-msvc@16.3.4':
|
||||
optional: true
|
||||
|
||||
'@noble/ciphers@1.3.0': {}
|
||||
@@ -11005,10 +11005,10 @@ snapshots:
|
||||
'@octokit/request-error': 6.1.8
|
||||
'@octokit/webhooks-methods': 5.1.1
|
||||
|
||||
'@openpanel/nextjs@1.5.1(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
|
||||
'@openpanel/nextjs@1.5.1(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
|
||||
dependencies:
|
||||
'@openpanel/web': 1.4.1
|
||||
next: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
next: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
|
||||
@@ -13540,7 +13540,7 @@ snapshots:
|
||||
dependencies:
|
||||
apg-lite: 1.0.5
|
||||
|
||||
'@swc/helpers@0.5.15':
|
||||
'@swc/helpers@0.5.23':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
@@ -13653,11 +13653,11 @@ snapshots:
|
||||
'@trpc/server': 11.10.0(typescript@7.0.2)
|
||||
typescript: 7.0.2
|
||||
|
||||
'@trpc/next@11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(react@19.2.7)(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)':
|
||||
'@trpc/next@11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/react-query@11.10.0(@tanstack/react-query@5.90.21(react@19.2.7))(@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(react@19.2.7)(typescript@7.0.2))(@trpc/server@11.10.0(typescript@7.0.2))(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)':
|
||||
dependencies:
|
||||
'@trpc/client': 11.10.0(@trpc/server@11.10.0(typescript@7.0.2))(typescript@7.0.2)
|
||||
'@trpc/server': 11.10.0(typescript@7.0.2)
|
||||
next: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
next: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
typescript: 7.0.2
|
||||
@@ -14266,7 +14266,7 @@ snapshots:
|
||||
|
||||
before-after-hook@2.2.3: {}
|
||||
|
||||
better-auth@1.6.23(165e0d14ffc9aaf8b4cab70e414c9093):
|
||||
better-auth@1.6.23(1f696af711ca01112337d810adfad25c):
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/drizzle-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.29.3)(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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))
|
||||
@@ -14292,43 +14292,7 @@ snapshots:
|
||||
drizzle-orm: 0.45.2(@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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.29.3)(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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
mongodb: 7.1.0(socks@2.8.8)
|
||||
mysql2: 3.15.3
|
||||
next: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
pg: 8.18.0
|
||||
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
vitest: 4.1.11(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(vite@7.3.1(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.8.1))
|
||||
transitivePeerDependencies:
|
||||
- '@cloudflare/workers-types'
|
||||
- '@opentelemetry/api'
|
||||
|
||||
better-auth@1.6.23(e687b32eb00a1602e570e2163c94e965):
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/drizzle-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.29.3)(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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))
|
||||
'@better-auth/kysely-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(kysely@0.29.3)
|
||||
'@better-auth/memory-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)
|
||||
'@better-auth/mongo-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(mongodb@7.1.0(socks@2.8.8))
|
||||
'@better-auth/prisma-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
'@better-auth/telemetry': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
'@better-fetch/fetch': 1.3.1
|
||||
'@noble/ciphers': 2.1.1
|
||||
'@noble/hashes': 2.0.1
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
defu: 6.1.7
|
||||
jose: 6.1.3
|
||||
kysely: 0.29.3
|
||||
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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
better-sqlite3: 12.6.2
|
||||
drizzle-kit: 0.31.9
|
||||
drizzle-orm: 0.45.2(@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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.29.3)(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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
mongodb: 7.1.0(socks@2.8.8)
|
||||
mysql2: 3.15.3
|
||||
next: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
next: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
pg: 8.18.0
|
||||
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)
|
||||
react: 19.2.7
|
||||
@@ -14338,6 +14302,42 @@ snapshots:
|
||||
- '@cloudflare/workers-types'
|
||||
- '@opentelemetry/api'
|
||||
|
||||
better-auth@1.6.23(9540743d27d6a8e6f2915ad16dc18aab):
|
||||
dependencies:
|
||||
'@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1)
|
||||
'@better-auth/drizzle-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.29.3)(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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))
|
||||
'@better-auth/kysely-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(kysely@0.29.3)
|
||||
'@better-auth/memory-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)
|
||||
'@better-auth/mongo-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(mongodb@7.1.0(socks@2.8.8))
|
||||
'@better-auth/prisma-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
'@better-auth/telemetry': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.3)(nanostores@1.1.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)
|
||||
'@better-auth/utils': 0.4.2
|
||||
'@better-fetch/fetch': 1.3.1
|
||||
'@noble/ciphers': 2.1.1
|
||||
'@noble/hashes': 2.0.1
|
||||
better-call: 1.3.7(zod@4.3.6)
|
||||
defu: 6.1.7
|
||||
jose: 6.1.3
|
||||
kysely: 0.29.3
|
||||
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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
better-sqlite3: 12.6.2
|
||||
drizzle-kit: 0.31.9
|
||||
drizzle-orm: 0.45.2(@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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.29.3)(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@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2))
|
||||
mongodb: 7.1.0(socks@2.8.8)
|
||||
mysql2: 3.15.3
|
||||
next: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
pg: 8.18.0
|
||||
prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
vitest: 4.1.11(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(vite@7.3.1(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.8.1))
|
||||
transitivePeerDependencies:
|
||||
- '@cloudflare/workers-types'
|
||||
- '@opentelemetry/api'
|
||||
|
||||
better-call@1.3.7(zod@4.3.6):
|
||||
dependencies:
|
||||
'@better-auth/utils': 0.4.2
|
||||
@@ -15747,7 +15747,7 @@ snapshots:
|
||||
|
||||
inline-style-parser@0.2.7: {}
|
||||
|
||||
inngest@3.40.1(encoding@0.1.13)(express@5.2.1)(h3@1.15.1)(hono@4.12.2)(next@16.3.0(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@7.0.2):
|
||||
inngest@3.40.1(encoding@0.1.13)(express@5.2.1)(h3@1.15.1)(hono@4.12.2)(next@16.3.4(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(typescript@7.0.2):
|
||||
dependencies:
|
||||
'@bufbuild/protobuf': 2.11.0
|
||||
'@inngest/ai': 0.1.7
|
||||
@@ -15775,7 +15775,7 @@ snapshots:
|
||||
express: 5.2.1
|
||||
h3: 1.15.1
|
||||
hono: 4.12.2
|
||||
next: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
next: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
typescript: 7.0.2
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
@@ -16577,16 +16577,16 @@ snapshots:
|
||||
|
||||
neotraverse@0.6.18: {}
|
||||
|
||||
next-themes@0.2.1(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
next-themes@0.2.1(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
dependencies:
|
||||
next: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
next: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
|
||||
next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
dependencies:
|
||||
'@next/env': 16.3.0
|
||||
'@swc/helpers': 0.5.15
|
||||
'@next/env': 16.3.4
|
||||
'@swc/helpers': 0.5.23
|
||||
baseline-browser-mapping: 2.10.0
|
||||
caniuse-lite: 1.0.30001774
|
||||
postcss: 8.5.23
|
||||
@@ -16594,24 +16594,24 @@ snapshots:
|
||||
react-dom: 19.2.7(react@19.2.7)
|
||||
styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.7)
|
||||
optionalDependencies:
|
||||
'@next/swc-darwin-arm64': 16.3.0
|
||||
'@next/swc-darwin-x64': 16.3.0
|
||||
'@next/swc-linux-arm64-gnu': 16.3.0
|
||||
'@next/swc-linux-arm64-musl': 16.3.0
|
||||
'@next/swc-linux-x64-gnu': 16.3.0
|
||||
'@next/swc-linux-x64-musl': 16.3.0
|
||||
'@next/swc-win32-arm64-msvc': 16.3.0
|
||||
'@next/swc-win32-x64-msvc': 16.3.0
|
||||
'@next/swc-darwin-arm64': 16.3.4
|
||||
'@next/swc-darwin-x64': 16.3.4
|
||||
'@next/swc-linux-arm64-gnu': 16.3.4
|
||||
'@next/swc-linux-arm64-musl': 16.3.4
|
||||
'@next/swc-linux-x64-gnu': 16.3.4
|
||||
'@next/swc-linux-x64-musl': 16.3.4
|
||||
'@next/swc-win32-arm64-msvc': 16.3.4
|
||||
'@next/swc-win32-x64-msvc': 16.3.4
|
||||
'@opentelemetry/api': 1.9.0
|
||||
sharp: 0.35.3(@types/node@24.10.13)
|
||||
sharp: 0.35.4(@types/node@24.10.13)
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
|
||||
nextjs-toploader@3.9.17(next@16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
nextjs-toploader@3.9.17(next@16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||
dependencies:
|
||||
next: 16.3.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
next: 16.3.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||
nprogress: 0.2.0
|
||||
prop-types: 15.8.1
|
||||
react: 19.2.7
|
||||
@@ -17822,37 +17822,37 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
sharp@0.35.3(@types/node@24.10.13):
|
||||
sharp@0.35.4(@types/node@24.10.13):
|
||||
dependencies:
|
||||
'@img/colour': 1.1.0
|
||||
detect-libc: 2.1.2
|
||||
semver: 7.8.5
|
||||
optionalDependencies:
|
||||
'@img/sharp-darwin-arm64': 0.35.3
|
||||
'@img/sharp-darwin-x64': 0.35.3
|
||||
'@img/sharp-freebsd-wasm32': 0.35.3
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.2
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.2
|
||||
'@img/sharp-libvips-linux-arm': 1.3.2
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.2
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.2
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.2
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.2
|
||||
'@img/sharp-libvips-linux-x64': 1.3.2
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.2
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.2
|
||||
'@img/sharp-linux-arm': 0.35.3
|
||||
'@img/sharp-linux-arm64': 0.35.3
|
||||
'@img/sharp-linux-ppc64': 0.35.3
|
||||
'@img/sharp-linux-riscv64': 0.35.3
|
||||
'@img/sharp-linux-s390x': 0.35.3
|
||||
'@img/sharp-linux-x64': 0.35.3
|
||||
'@img/sharp-linuxmusl-arm64': 0.35.3
|
||||
'@img/sharp-linuxmusl-x64': 0.35.3
|
||||
'@img/sharp-webcontainers-wasm32': 0.35.3
|
||||
'@img/sharp-win32-arm64': 0.35.3
|
||||
'@img/sharp-win32-ia32': 0.35.3
|
||||
'@img/sharp-win32-x64': 0.35.3
|
||||
'@img/sharp-darwin-arm64': 0.35.4
|
||||
'@img/sharp-darwin-x64': 0.35.4
|
||||
'@img/sharp-freebsd-wasm32': 0.35.4
|
||||
'@img/sharp-libvips-darwin-arm64': 1.3.3
|
||||
'@img/sharp-libvips-darwin-x64': 1.3.3
|
||||
'@img/sharp-libvips-linux-arm': 1.3.3
|
||||
'@img/sharp-libvips-linux-arm64': 1.3.3
|
||||
'@img/sharp-libvips-linux-ppc64': 1.3.3
|
||||
'@img/sharp-libvips-linux-riscv64': 1.3.3
|
||||
'@img/sharp-libvips-linux-s390x': 1.3.3
|
||||
'@img/sharp-libvips-linux-x64': 1.3.3
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.3
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.3
|
||||
'@img/sharp-linux-arm': 0.35.4
|
||||
'@img/sharp-linux-arm64': 0.35.4
|
||||
'@img/sharp-linux-ppc64': 0.35.4
|
||||
'@img/sharp-linux-riscv64': 0.35.4
|
||||
'@img/sharp-linux-s390x': 0.35.4
|
||||
'@img/sharp-linux-x64': 0.35.4
|
||||
'@img/sharp-linuxmusl-arm64': 0.35.4
|
||||
'@img/sharp-linuxmusl-x64': 0.35.4
|
||||
'@img/sharp-webcontainers-wasm32': 0.35.4
|
||||
'@img/sharp-win32-arm64': 0.35.4
|
||||
'@img/sharp-win32-ia32': 0.35.4
|
||||
'@img/sharp-win32-x64': 0.35.4
|
||||
'@types/node': 24.10.13
|
||||
optional: true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user