Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a265654ba5 | ||
|
|
30ec7d3105 |
@@ -1,18 +0,0 @@
|
||||
ARG VARIANT=18-bullseye
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:${VARIANT}
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
WORKDIR "/"
|
||||
|
||||
# Install fly
|
||||
RUN curl -L https://fly.io/install.sh | sh
|
||||
|
||||
ENV FLYCTL_INSTALL="/root/.fly"
|
||||
ENV PATH="$FLYCTL_INSTALL/bin:$PATH"
|
||||
|
||||
# RUN echo 'export FLYCTL_INSTALL="/home/node/.fly"' >> ~/.bashrc
|
||||
# RUN echo 'export PATH="$FLYCTL_INSTALL/bin:$PATH"' >> ~/.bashrc
|
||||
|
||||
RUN npm install -g bun
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "Comfy Deploy Dev",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||
"postCreateCommand": "cd web && bun install && bun run migrate-local",
|
||||
"remoteUser": "root",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"biomejs.biome",
|
||||
"formulahendry.auto-rename-tag",
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"stivo.tailwind-fold",
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"GitHub.copilot",
|
||||
"ms-azuretools.vscode-docker"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
|
||||
environment:
|
||||
VSCODE_DEV_CONTAINER: true
|
||||
|
||||
volumes:
|
||||
# Forwards the local Docker socket to the container.
|
||||
- /var/run/docker.sock:/var/run/docker-host.sock
|
||||
# Update this to wherever you want VS Code to mount the folder of your project
|
||||
- ../..:/workspaces:cached
|
||||
|
||||
# Overrides default command so things don't shut down after the process ends.
|
||||
# entrypoint: /usr/local/share/docker-init.sh
|
||||
command: sleep infinity
|
||||
postgres:
|
||||
image: "postgres:15.2-alpine"
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: verceldb
|
||||
ports:
|
||||
- "5480:5432"
|
||||
pg_proxy:
|
||||
image: ghcr.io/neondatabase/wsproxy:latest
|
||||
environment:
|
||||
APPEND_PORT: "postgres:5432"
|
||||
ALLOW_ADDR_REGEX: ".*"
|
||||
LOG_TRAFFIC: "true"
|
||||
ports:
|
||||
- "5481:80"
|
||||
depends_on:
|
||||
- postgres
|
||||
localstack:
|
||||
image: localstack/localstack:latest
|
||||
environment:
|
||||
SERVICES: s3
|
||||
ports:
|
||||
- 4566:4566
|
||||
volumes:
|
||||
- ../web/aws:/etc/localstack/init/ready.d
|
||||
- ../web/aws:/app/web/aws
|
||||
|
||||
Vendored
+8
-1
@@ -1,7 +1,14 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"DavidAnson.vscode-markdownlint", // markdown linting
|
||||
"yzhang.markdown-all-in-one", // nicer markdown support
|
||||
"esbenp.prettier-vscode", // prettier plugin
|
||||
"dbaeumer.vscode-eslint", // eslint plugin
|
||||
"bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind
|
||||
"ban.spellright", // Spell check for docs
|
||||
"biomejs.biome" // improved i18n DX
|
||||
"stripe.vscode-stripe", // stripe VSCode extension
|
||||
"Prisma.prisma", // syntax|format|completion for prisma
|
||||
"rebornix.project-snippets", // Share useful snippets between collaborators
|
||||
"inlang.vs-code-extension" // improved i18n DX
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+7
-5
@@ -1,16 +1,18 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSave": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"quickfix.biome": "always"
|
||||
// "source.organizeImports.biome": "explicit"
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"spellright.language": ["en"],
|
||||
"spellright.documentTypes": ["markdown", "typescript", "typescriptreact"],
|
||||
"tailwindCSS.experimental.classRegex": [
|
||||
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
|
||||
]
|
||||
[
|
||||
"cva\\(([^)]*)\\)",
|
||||
"[\"'`]([^\"'`]*).*?[\"'`]"
|
||||
]
|
||||
],
|
||||
// "eslint.workingDirectories": [
|
||||
// { "mode": "auto" }
|
||||
// ],
|
||||
|
||||
@@ -75,11 +75,10 @@ Major areas
|
||||
3. `bun i`
|
||||
4. Start docker
|
||||
5. `cp .env.example .env.local`
|
||||
6. Replace `JWT_SECRET` with `openssl rand -hex 32`
|
||||
6. Repace `JWT_SECRET` with `openssl rand -hex 32`
|
||||
7. Get a local clerk dev key for `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`
|
||||
8. Keep a terminal live for `bun run db-dev`
|
||||
9. Execute the local migration to create the initial data `bun run migrate-local`
|
||||
10. Finally start the next server with `bun dev`
|
||||
9. Finally start the next server with `bun dev`
|
||||
|
||||
**Schema Changes**
|
||||
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"$schema": "./web/node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"formatter": {
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": false,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"parser": {
|
||||
"allowComments": true
|
||||
}
|
||||
},
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true,
|
||||
"defaultBranch": "main"
|
||||
}
|
||||
}
|
||||
@@ -312,8 +312,7 @@ async def build_logic(item: Item):
|
||||
config = {
|
||||
"name": item.name,
|
||||
"deploy_test": os.environ.get("DEPLOY_TEST_FLAG", "False"),
|
||||
"gpu": item.gpu,
|
||||
"civitai_token": os.environ.get("CIVITAI_TOKEN", "")
|
||||
"gpu": item.gpu
|
||||
}
|
||||
with open(f"{folder_path}/config.py", "w") as f:
|
||||
f.write("config = " + json.dumps(config))
|
||||
|
||||
@@ -36,9 +36,6 @@ if not deploy_test:
|
||||
|
||||
dockerfile_image = (
|
||||
modal.Image.debian_slim()
|
||||
.env({
|
||||
"CIVITAI_TOKEN": config["civitai_token"],
|
||||
})
|
||||
.apt_install("git", "wget")
|
||||
.pip_install(
|
||||
"git+https://github.com/modal-labs/asgiproxy.git", "httpx", "tqdm"
|
||||
@@ -234,8 +231,7 @@ def run(input: Input):
|
||||
async def bar(request_input: RequestInput):
|
||||
# print(request_input)
|
||||
if not deploy_test:
|
||||
run.spawn(request_input.input)
|
||||
return {"status": "success"}
|
||||
return run.remote(request_input.input)
|
||||
# pass
|
||||
|
||||
|
||||
|
||||
@@ -49,12 +49,6 @@ with open('models.json') as f:
|
||||
models = json.load(f)
|
||||
|
||||
for model in models:
|
||||
import os
|
||||
if "civitai.com/api" in model['url'] and not "token=" in model['url']:
|
||||
if "?" in model['url']:
|
||||
model['url'] += "&token=" + os.environ.get('CIVITAI_TOKEN', '')
|
||||
else:
|
||||
model['url'] += "?token=" + os.environ.get('CIVITAI_TOKEN', '')
|
||||
response = requests.request("POST", f"{root_url}/model/install", json=model, headers=headers)
|
||||
print(response.text)
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import folder_paths
|
||||
from PIL import Image, ImageOps
|
||||
import numpy as np
|
||||
import torch
|
||||
import folder_paths
|
||||
from tqdm import tqdm
|
||||
|
||||
class ComfyUIDeployExternalCheckpoint:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"input_id": (
|
||||
"STRING",
|
||||
{"multiline": False, "default": "input_checkpoint"},
|
||||
),
|
||||
},
|
||||
"optional": {
|
||||
"default_checkpoint_name": (folder_paths.get_filename_list("checkpoints"), ),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = (folder_paths.get_filename_list("checkpoints"),)
|
||||
RETURN_NAMES = ("path",)
|
||||
|
||||
FUNCTION = "run"
|
||||
|
||||
CATEGORY = "deploy"
|
||||
|
||||
def run(self, input_id, default_checkpoint_name=None):
|
||||
import requests
|
||||
import os
|
||||
import uuid
|
||||
|
||||
if input_id and input_id.startswith('http'):
|
||||
unique_filename = str(uuid.uuid4()) + ".safetensors"
|
||||
print(unique_filename)
|
||||
print(folder_paths.folder_names_and_paths["checkpoints"][0][0])
|
||||
destination_path = os.path.join(
|
||||
folder_paths.folder_names_and_paths["checkpoints"][0][0], unique_filename)
|
||||
print(destination_path)
|
||||
print("Downloading external checkpoint - " +
|
||||
input_id + " to " + destination_path)
|
||||
response = requests.get(
|
||||
input_id, headers={'User-Agent': 'Mozilla/5.0'}, allow_redirects=True, stream=True)
|
||||
file_size = int(response.headers.get('Content-Length', 0))
|
||||
chunk = 1
|
||||
chunk_size = 1024
|
||||
num_bars = int(file_size / chunk_size)
|
||||
|
||||
with open(destination_path, 'wb') as out_file:
|
||||
for chunk in tqdm(
|
||||
response.iter_content(chunk_size=chunk_size),
|
||||
total=num_bars,
|
||||
unit='KB',
|
||||
desc="Downloading",
|
||||
leave=True # leave=True to keep progress bars
|
||||
):
|
||||
out_file.write(chunk)
|
||||
return (unique_filename,)
|
||||
else:
|
||||
return (default_checkpoints_name,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ComfyUIDeployExternalCheckpoint": ComfyUIDeployExternalCheckpoint}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ComfyUIDeployExternalCheckpoint": "External Checkpoint (ComfyUI Deploy)"}
|
||||
@@ -29,7 +29,9 @@ class ComfyUIDeployExternalText:
|
||||
CATEGORY = "text"
|
||||
|
||||
def run(self, input_id, default_value=None):
|
||||
return [default_value]
|
||||
if not input_id or len(input_id.strip()) == 0:
|
||||
return [default_value]
|
||||
return [input_id]
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalText": ComfyUIDeployExternalText}
|
||||
|
||||
+17
-234
@@ -22,14 +22,10 @@ from logging.handlers import RotatingFileHandler
|
||||
from enum import Enum
|
||||
from urllib.parse import quote
|
||||
import threading
|
||||
import hashlib
|
||||
import aiohttp
|
||||
|
||||
api = None
|
||||
api_task = None
|
||||
prompt_metadata = {}
|
||||
cd_enable_log = os.environ.get('CD_ENABLE_LOG', 'false').lower() == 'true'
|
||||
cd_enable_run_log = os.environ.get('CD_ENABLE_RUN_LOG', 'false').lower() == 'true'
|
||||
|
||||
def post_prompt(json_data):
|
||||
prompt_server = server.PromptServer.instance
|
||||
@@ -101,7 +97,6 @@ async def comfy_deploy_run(request):
|
||||
prompt_metadata[prompt_id] = {
|
||||
'status_endpoint': data.get('status_endpoint'),
|
||||
'file_upload_endpoint': data.get('file_upload_endpoint'),
|
||||
'workflow_api': workflow_api
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -118,8 +113,6 @@ async def comfy_deploy_run(request):
|
||||
"stack_trace": stack_trace
|
||||
}
|
||||
})
|
||||
# When there are critical errors, the prompt is actually not run
|
||||
await update_run(prompt_id, Status.FAILED)
|
||||
return web.Response(status=500, reason=f"{error_type}: {e}, {stack_trace_short}")
|
||||
|
||||
status = 200
|
||||
@@ -148,138 +141,6 @@ async def comfy_deploy_run(request):
|
||||
|
||||
sockets = dict()
|
||||
|
||||
def get_comfyui_path_from_file_path(file_path):
|
||||
file_path_parts = file_path.split("\\")
|
||||
|
||||
if file_path_parts[0] == "input":
|
||||
print("matching input")
|
||||
file_path = os.path.join(folder_paths.get_directory_by_type("input"), *file_path_parts[1:])
|
||||
elif file_path_parts[0] == "models":
|
||||
print("matching models")
|
||||
file_path = folder_paths.get_full_path(file_path_parts[1], os.path.join(*file_path_parts[2:]))
|
||||
|
||||
print(file_path)
|
||||
|
||||
return file_path
|
||||
|
||||
# Form ComfyUI Manager
|
||||
def compute_sha256_checksum(filepath):
|
||||
filepath = get_comfyui_path_from_file_path(filepath)
|
||||
"""Compute the SHA256 checksum of a file, in chunks"""
|
||||
sha256 = hashlib.sha256()
|
||||
with open(filepath, 'rb') as f:
|
||||
for chunk in iter(lambda: f.read(4096), b''):
|
||||
sha256.update(chunk)
|
||||
return sha256.hexdigest()
|
||||
|
||||
# This is start uploading the files to Comfy Deploy
|
||||
@server.PromptServer.instance.routes.post('/comfyui-deploy/upload-file')
|
||||
async def upload_file(request):
|
||||
data = await request.json()
|
||||
|
||||
file_path = data.get("file_path")
|
||||
|
||||
print("Original file path", file_path)
|
||||
|
||||
file_path = get_comfyui_path_from_file_path(file_path)
|
||||
|
||||
# return web.json_response({
|
||||
# "error": f"File not uploaded"
|
||||
# }, status=500)
|
||||
|
||||
token = data.get("token")
|
||||
get_url = data.get("url")
|
||||
|
||||
try:
|
||||
base = folder_paths.base_path
|
||||
file_path = os.path.join(base, file_path)
|
||||
|
||||
if os.path.exists(file_path):
|
||||
file_size = os.path.getsize(file_path)
|
||||
file_extension = os.path.splitext(file_path)[1]
|
||||
|
||||
if file_extension in ['.jpg', '.jpeg']:
|
||||
file_type = 'image/jpeg'
|
||||
elif file_extension == '.png':
|
||||
file_type = 'image/png'
|
||||
elif file_extension == '.webp':
|
||||
file_type = 'image/webp'
|
||||
else:
|
||||
file_type = 'application/octet-stream' # Default to binary file type if unknown
|
||||
else:
|
||||
return web.json_response({
|
||||
"error": f"File not found: {file_path}"
|
||||
}, status=404)
|
||||
|
||||
except Exception as e:
|
||||
return web.json_response({
|
||||
"error": str(e)
|
||||
}, status=500)
|
||||
|
||||
if get_url:
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
headers = {'Authorization': f'Bearer {token}'}
|
||||
params = {'file_size': file_size, 'type': file_type}
|
||||
async with session.get(get_url, params=params, headers=headers) as response:
|
||||
if response.status == 200:
|
||||
content = await response.json()
|
||||
upload_url = content["upload_url"]
|
||||
|
||||
with open(file_path, 'rb') as f:
|
||||
headers = {
|
||||
"Content-Type": file_type,
|
||||
"x-amz-acl": "public-read",
|
||||
"Content-Length": str(file_size)
|
||||
}
|
||||
async with session.put(upload_url, data=f, headers=headers) as upload_response:
|
||||
if upload_response.status == 200:
|
||||
return web.json_response({
|
||||
"message": "File uploaded successfully",
|
||||
"download_url": content["download_url"]
|
||||
})
|
||||
else:
|
||||
return web.json_response({
|
||||
"error": f"Failed to upload file to {upload_url}. Status code: {upload_response.status}"
|
||||
}, status=upload_response.status)
|
||||
else:
|
||||
return web.json_response({
|
||||
"error": f"Failed to fetch data from {get_url}. Status code: {response.status}"
|
||||
}, status=response.status)
|
||||
except Exception as e:
|
||||
return web.json_response({
|
||||
"error": f"An error occurred while fetching data from {get_url}: {str(e)}"
|
||||
}, status=500)
|
||||
|
||||
return web.json_response({
|
||||
"error": f"File not uploaded"
|
||||
}, status=500)
|
||||
|
||||
|
||||
@server.PromptServer.instance.routes.get('/comfyui-deploy/get-file-hash')
|
||||
async def get_file_hash(request):
|
||||
file_path = request.rel_url.query.get('file_path', '')
|
||||
|
||||
if file_path is None:
|
||||
return web.json_response({
|
||||
"error": "file_path is required"
|
||||
}, status=400)
|
||||
|
||||
try:
|
||||
base = folder_paths.base_path
|
||||
file_path = os.path.join(base, file_path)
|
||||
# print("file_path", file_path)
|
||||
file_hash = compute_sha256_checksum(
|
||||
file_path
|
||||
)
|
||||
return web.json_response({
|
||||
"file_hash": file_hash
|
||||
})
|
||||
except Exception as e:
|
||||
return web.json_response({
|
||||
"error": str(e)
|
||||
}, status=500)
|
||||
|
||||
@server.PromptServer.instance.routes.get('/comfyui-deploy/ws')
|
||||
async def websocket_handler(request):
|
||||
ws = web.WebSocketResponse()
|
||||
@@ -296,9 +157,7 @@ async def websocket_handler(request):
|
||||
try:
|
||||
# Send initial state to the new client
|
||||
await send("status", { 'sid': sid }, sid)
|
||||
|
||||
if cd_enable_log:
|
||||
await send_first_time_log(sid)
|
||||
await send_first_time_log(sid)
|
||||
|
||||
async for msg in ws:
|
||||
if msg.type == aiohttp.WSMsgType.ERROR:
|
||||
@@ -344,10 +203,7 @@ async def send_json_override(self, event, data, sid=None):
|
||||
prompt_id = data.get('prompt_id')
|
||||
|
||||
# now we send everything
|
||||
await asyncio.wait([
|
||||
asyncio.create_task(send(event, data)),
|
||||
asyncio.create_task(self.send_json_original(event, data, sid))
|
||||
])
|
||||
await asyncio.wait([send(event, data), self.send_json_original(event, data, sid)])
|
||||
|
||||
if event == 'execution_start':
|
||||
update_run(prompt_id, Status.RUNNING)
|
||||
@@ -358,17 +214,6 @@ async def send_json_override(self, event, data, sid=None):
|
||||
if not have_pending_upload(prompt_id):
|
||||
update_run(prompt_id, Status.SUCCESS)
|
||||
|
||||
if event == 'executing' and data.get('node') is not None:
|
||||
node = data.get('node')
|
||||
|
||||
if 'prompt_id' in prompt_metadata:
|
||||
if 'last_updated_node' in prompt_metadata[prompt_id] and prompt_metadata[prompt_id]['last_updated_node'] == node:
|
||||
return
|
||||
prompt_metadata[prompt_id]['last_updated_node'] = node
|
||||
class_type = prompt_metadata[prompt_id]['workflow_api'][node]['class_type']
|
||||
print("updating run live status", class_type)
|
||||
await update_run_live_status(prompt_id, "Executing " + class_type)
|
||||
|
||||
if event == 'execution_error':
|
||||
# Careful this might not be fully awaited.
|
||||
await update_run_with_output(prompt_id, data)
|
||||
@@ -388,26 +233,7 @@ class Status(Enum):
|
||||
FAILED = "failed"
|
||||
UPLOADING = "uploading"
|
||||
|
||||
# Global variable to keep track of the last read line number
|
||||
last_read_line_number = 0
|
||||
|
||||
async def update_run_live_status(prompt_id, live_status):
|
||||
if prompt_id not in prompt_metadata:
|
||||
return
|
||||
|
||||
status_endpoint = prompt_metadata[prompt_id]['status_endpoint']
|
||||
body = {
|
||||
"run_id": prompt_id,
|
||||
"live_status": live_status,
|
||||
}
|
||||
# requests.post(status_endpoint, json=body)
|
||||
async with aiohttp.ClientSession() as session:
|
||||
await session.post(status_endpoint, json=body)
|
||||
|
||||
|
||||
def update_run(prompt_id, status: Status):
|
||||
global last_read_line_number
|
||||
|
||||
if prompt_id not in prompt_metadata:
|
||||
return
|
||||
|
||||
@@ -422,50 +248,16 @@ def update_run(prompt_id, status: Status):
|
||||
"run_id": prompt_id,
|
||||
"status": status.value,
|
||||
}
|
||||
prompt_metadata[prompt_id]['status'] = status
|
||||
print(f"Status: {status.value}")
|
||||
|
||||
try:
|
||||
requests.post(status_endpoint, json=body)
|
||||
|
||||
if cd_enable_run_log and (status == Status.SUCCESS or status == Status.FAILED):
|
||||
try:
|
||||
with open(comfyui_file_path, 'r') as log_file:
|
||||
# log_data = log_file.read()
|
||||
# Move to the last read line
|
||||
all_log_data = log_file.read() # Read all log data
|
||||
print("All log data before skipping:", all_log_data) # Log all data before skipping
|
||||
log_file.seek(0) # Reset file pointer to the beginning
|
||||
|
||||
for _ in range(last_read_line_number):
|
||||
next(log_file)
|
||||
log_data = log_file.read()
|
||||
# Update the last read line number
|
||||
last_read_line_number += log_data.count('\n')
|
||||
print("last_read_line_number", last_read_line_number)
|
||||
print("log_data", log_data)
|
||||
print("log_data.count(n)", log_data.count('\n'))
|
||||
|
||||
body = {
|
||||
"run_id": prompt_id,
|
||||
"log_data": [
|
||||
{
|
||||
"logs": log_data,
|
||||
# "timestamp": time.time(),
|
||||
}
|
||||
]
|
||||
}
|
||||
requests.post(status_endpoint, json=body)
|
||||
except Exception as log_error:
|
||||
print(f"Error reading log file: {log_error}")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
error_type = type(e).__name__
|
||||
stack_trace = traceback.format_exc().strip()
|
||||
print(f"Error occurred while updating run: {e} {stack_trace}")
|
||||
finally:
|
||||
prompt_metadata[prompt_id]['status'] = status
|
||||
|
||||
|
||||
|
||||
async def upload_file(prompt_id, filename, subfolder=None, content_type="image/png", type="output"):
|
||||
"""
|
||||
@@ -515,9 +307,7 @@ async def upload_file(prompt_id, filename, subfolder=None, content_type="image/p
|
||||
"Content-Length": str(len(data)),
|
||||
}
|
||||
response = requests.put(ok.get("url"), headers=headers, data=data)
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.put(ok.get("url"), headers=headers, data=data) as response:
|
||||
print("upload file response", response.status)
|
||||
print("upload file response", response.status_code)
|
||||
|
||||
def have_pending_upload(prompt_id):
|
||||
if 'prompt_id' in prompt_metadata and 'uploading_nodes' in prompt_metadata[prompt_id] and len(prompt_metadata[prompt_id]['uploading_nodes']) > 0:
|
||||
@@ -594,25 +384,20 @@ async def update_file_status(prompt_id, data, uploading, have_error=False, node_
|
||||
"prompt_id": prompt_id,
|
||||
})
|
||||
|
||||
async def handle_upload(prompt_id, data, key, content_type_key, default_content_type):
|
||||
items = data.get(key, [])
|
||||
for item in items:
|
||||
await upload_file(
|
||||
prompt_id,
|
||||
item.get("filename"),
|
||||
subfolder=item.get("subfolder"),
|
||||
type=item.get("type"),
|
||||
content_type=item.get(content_type_key, default_content_type)
|
||||
)
|
||||
|
||||
|
||||
# Upload files in the background
|
||||
async def upload_in_background(prompt_id, data, node_id=None, have_upload=True):
|
||||
try:
|
||||
await handle_upload(prompt_id, data, 'images', "content_type", "image/png")
|
||||
await handle_upload(prompt_id, data, 'files', "content_type", "image/png")
|
||||
# This will also be mp4
|
||||
await handle_upload(prompt_id, data, 'gifs', "format", "image/gif")
|
||||
images = data.get('images', [])
|
||||
for image in images:
|
||||
await upload_file(prompt_id, image.get("filename"), subfolder=image.get("subfolder"), type=image.get("type"), content_type=image.get("content_type", "image/png"))
|
||||
|
||||
files = data.get('files', [])
|
||||
for file in files:
|
||||
await upload_file(prompt_id, file.get("filename"), subfolder=file.get("subfolder"), type=file.get("type"), content_type=file.get("content_type", "image/png"))
|
||||
|
||||
gifs = data.get('gifs', [])
|
||||
for gif in gifs:
|
||||
await upload_file(prompt_id, gif.get("filename"), subfolder=gif.get("subfolder"), type=gif.get("type"), content_type=gif.get("format", "image/gif"))
|
||||
|
||||
if have_upload:
|
||||
await update_file_status(prompt_id, data, False, node_id=node_id)
|
||||
@@ -653,7 +438,6 @@ prompt_server.send_json = send_json_override.__get__(prompt_server, server.Promp
|
||||
root_path = os.path.dirname(os.path.abspath(__file__))
|
||||
two_dirs_up = os.path.dirname(os.path.dirname(root_path))
|
||||
log_file_path = os.path.join(two_dirs_up, 'comfy-deploy.log')
|
||||
comfyui_file_path = os.path.join(two_dirs_up, 'comfyui.log')
|
||||
|
||||
last_read_line = 0
|
||||
|
||||
@@ -693,5 +477,4 @@ def run_in_new_thread(coroutine):
|
||||
t.start()
|
||||
asyncio.run_coroutine_threadsafe(coroutine, new_loop)
|
||||
|
||||
if cd_enable_log:
|
||||
run_in_new_thread(watch_file_changes(log_file_path, send_logs_to_websocket))
|
||||
run_in_new_thread(watch_file_changes(log_file_path, send_logs_to_websocket))
|
||||
|
||||
+32
-43
@@ -7,56 +7,45 @@ import threading
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
# Running with export CD_ENABLE_LOG=true; python main.py
|
||||
handler = RotatingFileHandler('comfy-deploy.log', maxBytes=500000, backupCount=5)
|
||||
|
||||
# Check for 'cd-enable-log' flag in input arguments
|
||||
# cd_enable_log = '--cd-enable-log' in sys.argv
|
||||
cd_enable_log = os.environ.get('CD_ENABLE_LOG', 'false').lower() == 'true'
|
||||
original_stdout = sys.stdout
|
||||
original_stderr = sys.stderr
|
||||
|
||||
def setup():
|
||||
handler = RotatingFileHandler('comfy-deploy.log', maxBytes=500000, backupCount=5)
|
||||
class StreamToLogger():
|
||||
def __init__(self, log_level):
|
||||
self.log_level = log_level
|
||||
|
||||
original_stdout = sys.stdout
|
||||
original_stderr = sys.stderr
|
||||
def write(self, buf):
|
||||
if (self.log_level == logging.INFO):
|
||||
original_stdout.write(buf)
|
||||
original_stdout.flush()
|
||||
elif (self.log_level == logging.ERROR):
|
||||
original_stderr.write(buf)
|
||||
original_stderr.flush()
|
||||
|
||||
class StreamToLogger():
|
||||
def __init__(self, log_level):
|
||||
self.log_level = log_level
|
||||
|
||||
def write(self, buf):
|
||||
if (self.log_level == logging.INFO):
|
||||
original_stdout.write(buf)
|
||||
original_stdout.flush()
|
||||
elif (self.log_level == logging.ERROR):
|
||||
original_stderr.write(buf)
|
||||
original_stderr.flush()
|
||||
|
||||
for line in buf.rstrip().splitlines():
|
||||
handler.handle(
|
||||
logging.LogRecord(
|
||||
name="comfy-deploy",
|
||||
level=self.log_level,
|
||||
pathname="prestartup_script.py",
|
||||
lineno=1,
|
||||
msg=line.rstrip(),
|
||||
args=None,
|
||||
exc_info=None
|
||||
)
|
||||
for line in buf.rstrip().splitlines():
|
||||
handler.handle(
|
||||
logging.LogRecord(
|
||||
name="comfy-deploy",
|
||||
level=self.log_level,
|
||||
pathname="prestartup_script.py",
|
||||
lineno=1,
|
||||
msg=line.rstrip(),
|
||||
args=None,
|
||||
exc_info=None
|
||||
)
|
||||
)
|
||||
|
||||
def flush(self):
|
||||
if (self.log_level == logging.INFO):
|
||||
original_stdout.flush()
|
||||
elif (self.log_level == logging.ERROR):
|
||||
original_stderr.flush()
|
||||
def flush(self):
|
||||
if (self.log_level == logging.INFO):
|
||||
original_stdout.flush()
|
||||
elif (self.log_level == logging.ERROR):
|
||||
original_stderr.flush()
|
||||
|
||||
# Redirect stdout and stderr to the logger
|
||||
sys.stdout = StreamToLogger(logging.INFO)
|
||||
sys.stderr = StreamToLogger(logging.ERROR)
|
||||
|
||||
if cd_enable_log:
|
||||
print("** Comfy Deploy logging enabled")
|
||||
setup()
|
||||
# Redirect stdout and stderr to the logger
|
||||
sys.stdout = StreamToLogger(logging.INFO)
|
||||
sys.stderr = StreamToLogger(logging.ERROR)
|
||||
|
||||
try:
|
||||
# Get the absolute path of the script's directory
|
||||
|
||||
+49
-429
@@ -1,7 +1,6 @@
|
||||
import { app } from "./app.js";
|
||||
import { api } from "./api.js";
|
||||
import { ComfyWidgets, LGraphNode } from "./widgets.js";
|
||||
import { generateDependencyGraph } from "https://esm.sh/[email protected]";
|
||||
|
||||
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
|
||||
/** @type {ComfyExtension} */
|
||||
@@ -10,76 +9,6 @@ const ext = {
|
||||
|
||||
init(app) {
|
||||
addButton();
|
||||
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
const workflow_version_id = queryParams.get("workflow_version_id");
|
||||
const auth_token = queryParams.get("auth_token");
|
||||
const org_display = queryParams.get("org_display");
|
||||
const origin = queryParams.get("origin");
|
||||
|
||||
const data = getData();
|
||||
let endpoint = data.endpoint;
|
||||
let apiKey = data.apiKey;
|
||||
|
||||
// If there is auth token override it
|
||||
if (auth_token) {
|
||||
apiKey = auth_token;
|
||||
endpoint = origin;
|
||||
saveData({
|
||||
displayName: org_display,
|
||||
endpoint: origin,
|
||||
apiKey: auth_token,
|
||||
displayName: org_display,
|
||||
environment: "cloud",
|
||||
});
|
||||
localStorage.setItem("comfy_deploy_env", "cloud");
|
||||
}
|
||||
|
||||
if (!workflow_version_id) {
|
||||
console.error("No workflow_version_id provided in query parameters.");
|
||||
} else {
|
||||
loadingDialog.showLoading(
|
||||
"Loading workflow from " + org_display,
|
||||
"Please wait...",
|
||||
);
|
||||
fetch(endpoint + "/api/workflow-version/" + workflow_version_id, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + apiKey,
|
||||
},
|
||||
})
|
||||
.then(async (res) => {
|
||||
const data = await res.json();
|
||||
const { workflow, workflow_id, error } = data;
|
||||
if (error) {
|
||||
infoDialog.showMessage("Unable to load this workflow", error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Adding a delay to wait for the intial graph to load
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
|
||||
workflow?.nodes.forEach((x) => {
|
||||
if (x?.type === "ComfyDeploy") {
|
||||
x.widgets_values[1] = workflow_id;
|
||||
// x.widgets_values[2] = workflow_version.version;
|
||||
}
|
||||
});
|
||||
|
||||
/** @type {LGraph} */
|
||||
app.loadGraphData(workflow);
|
||||
})
|
||||
.catch((e) => infoDialog.showMessage("Error", e.message))
|
||||
.finally(() => {
|
||||
loadingDialog.close();
|
||||
window.history.replaceState(
|
||||
{},
|
||||
document.title,
|
||||
window.location.pathname,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
registerCustomNodes() {
|
||||
@@ -179,92 +108,6 @@ function showError(title, message) {
|
||||
);
|
||||
}
|
||||
|
||||
function createDynamicUIHtml(data) {
|
||||
console.log(data);
|
||||
let html =
|
||||
'<div style="max-width: 1024px; margin: 14px auto; display: flex; flex-direction: column; gap: 24px;">';
|
||||
const bgcolor = "var(--comfy-input-bg)";
|
||||
const evenBg = "var(--border-color)";
|
||||
const textColor = "var(--input-text)";
|
||||
|
||||
// Custom Nodes
|
||||
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||
html +=
|
||||
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Custom Nodes</h2>';
|
||||
|
||||
if (data.missing_nodes?.length > 0) {
|
||||
html += `
|
||||
<div style="border-bottom: 1px solid #e2e8f0; padding: 4px 12px; background-color: ${evenBg}">
|
||||
<h3 style="font-size: 14px; font-weight: semibold; margin-bottom: 8px;">Missing Nodes</h3>
|
||||
<p style="font-size: 12px;">These nodes are not found with any matching custom_nodes in the ComfyUI Manager Database</p>
|
||||
${data.missing_nodes
|
||||
.map((node) => {
|
||||
return `<p style="font-size: 14px; color: #d69e2e;">${node}</p>`;
|
||||
})
|
||||
.join("")}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Object.values(data.custom_nodes).forEach((node) => {
|
||||
html += `
|
||||
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 16px;">
|
||||
<a href="${
|
||||
node.url
|
||||
}" target="_blank" style="font-size: 18px; font-weight: semibold; color: white; text-decoration: none;">${
|
||||
node.name
|
||||
}</a>
|
||||
<p style="font-size: 14px; color: #4b5563;">${node.hash}</p>
|
||||
${
|
||||
node.warning
|
||||
? `<p style="font-size: 14px; color: #d69e2e;">${node.warning}</p>`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
html += "</div>";
|
||||
|
||||
// Models
|
||||
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||
html +=
|
||||
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Models</h2>';
|
||||
|
||||
Object.entries(data.models).forEach(([section, items]) => {
|
||||
html += `
|
||||
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||
section.charAt(0).toUpperCase() + section.slice(1)
|
||||
}</h3>`;
|
||||
items.forEach((item) => {
|
||||
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||
});
|
||||
html += "</div>";
|
||||
});
|
||||
html += "</div>";
|
||||
|
||||
// Models
|
||||
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||
html +=
|
||||
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Files</h2>';
|
||||
|
||||
Object.entries(data.files).forEach(([section, items]) => {
|
||||
html += `
|
||||
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||
section.charAt(0).toUpperCase() + section.slice(1)
|
||||
}</h3>`;
|
||||
items.forEach((item) => {
|
||||
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||
});
|
||||
html += "</div>";
|
||||
});
|
||||
html += "</div>";
|
||||
|
||||
html += "</div>";
|
||||
return html;
|
||||
}
|
||||
|
||||
function addButton() {
|
||||
const menu = document.querySelector(".comfy-menu");
|
||||
|
||||
@@ -276,29 +119,8 @@ function addButton() {
|
||||
/** @type {LGraph} */
|
||||
const graph = app.graph;
|
||||
|
||||
let { endpoint, apiKey, displayName } = getData();
|
||||
|
||||
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
|
||||
configDialog.show();
|
||||
return;
|
||||
}
|
||||
|
||||
const ok = await confirmDialog.confirm(
|
||||
"Confirm deployment -> " + displayName,
|
||||
`A new version will be deployed, are you conform? <br><br><input id="include-deps" type="checkbox" checked>Include dependence</input>`,
|
||||
);
|
||||
if (!ok) return;
|
||||
|
||||
const includeDeps = document.getElementById("include-deps").checked;
|
||||
|
||||
if (endpoint.endsWith("/")) {
|
||||
endpoint = endpoint.slice(0, -1);
|
||||
}
|
||||
loadingDialog.showLoading("Generating snapshot", "Please wait...");
|
||||
|
||||
const snapshot = await fetch("/snapshot/get_current").then((x) => x.json());
|
||||
// console.log(snapshot);
|
||||
loadingDialog.close();
|
||||
console.log(snapshot);
|
||||
|
||||
if (!snapshot) {
|
||||
showError(
|
||||
@@ -332,122 +154,52 @@ function addButton() {
|
||||
|
||||
const deployMetaNode = deployMeta[0];
|
||||
|
||||
console.log(deployMetaNode);
|
||||
|
||||
const workflow_name = deployMetaNode.widgets[0].value;
|
||||
const workflow_id = deployMetaNode.widgets[1].value;
|
||||
|
||||
console.log(workflow_name, workflow_id);
|
||||
|
||||
const prompt = await app.graphToPrompt();
|
||||
let deps = undefined;
|
||||
console.log(graph);
|
||||
console.log(prompt);
|
||||
|
||||
if (includeDeps) {
|
||||
loadingDialog.showLoading("Fetching existing version", "Please wait...");
|
||||
// const endpoint = localStorage.getItem("endpoint") ?? "";
|
||||
// const apiKey = localStorage.getItem("apiKey");
|
||||
|
||||
const existing_workflow = await fetch(
|
||||
endpoint + "/api/workflow/" + workflow_id,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + apiKey,
|
||||
},
|
||||
},
|
||||
)
|
||||
.then((x) => x.json())
|
||||
.catch(() => {
|
||||
return {};
|
||||
});
|
||||
const { endpoint, apiKey } = getData();
|
||||
|
||||
loadingDialog.close();
|
||||
|
||||
loadingDialog.showLoading(
|
||||
"Generating dependency graph",
|
||||
"Please wait...",
|
||||
);
|
||||
deps = await generateDependencyGraph({
|
||||
workflow_api: prompt.output,
|
||||
snapshot: snapshot,
|
||||
computeFileHash: async (file) => {
|
||||
console.log(file);
|
||||
loadingDialog.showLoading("Generating hash", file);
|
||||
const hash = await fetch(
|
||||
`/comfyui-deploy/get-file-hash?file_path=${encodeURIComponent(
|
||||
file,
|
||||
)}`,
|
||||
).then((x) => x.json());
|
||||
loadingDialog.showLoading("Generating hash", file);
|
||||
console.log(hash);
|
||||
return hash.file_hash;
|
||||
},
|
||||
handleFileUpload: async (file, hash, prevhash) => {
|
||||
console.log("Uploading ", file);
|
||||
loadingDialog.showLoading("Uploading file", file);
|
||||
try {
|
||||
const { download_url } = await fetch(
|
||||
`/comfyui-deploy/upload-file`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
file_path: file,
|
||||
token: apiKey,
|
||||
url: endpoint + "/api/upload-url",
|
||||
}),
|
||||
},
|
||||
)
|
||||
.then((x) => x.json())
|
||||
.catch(() => {
|
||||
loadingDialog.close();
|
||||
confirmDialog.confirm("Error", "Unable to upload file " + file);
|
||||
});
|
||||
loadingDialog.showLoading("Uploaded file", file);
|
||||
console.log(download_url);
|
||||
return download_url;
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
existingDependencies: existing_workflow.dependencies,
|
||||
});
|
||||
|
||||
loadingDialog.close();
|
||||
|
||||
const depsOk = await confirmDialog.confirm(
|
||||
"Check dependencies",
|
||||
// JSON.stringify(deps, null, 2),
|
||||
createDynamicUIHtml(deps),
|
||||
);
|
||||
if (!depsOk) return;
|
||||
|
||||
console.log(deps);
|
||||
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
|
||||
configDialog.show();
|
||||
return;
|
||||
}
|
||||
|
||||
loadingDialog.showLoading("Deploying...");
|
||||
const ok = await confirmDialog.confirm("Confirm deployment", "A new version will be deployed, are you conform?")
|
||||
if (!ok) return;
|
||||
|
||||
title.innerText = "Deploying...";
|
||||
title.style.color = "orange";
|
||||
|
||||
// console.log(prompt);
|
||||
console.log(prompt);
|
||||
|
||||
// TODO trim the ending / from endpoint is there is
|
||||
if (endpoint.endsWith("/")) {
|
||||
endpoint = endpoint.slice(0, -1);
|
||||
}
|
||||
|
||||
// console.log(prompt.workflow);
|
||||
|
||||
const apiRoute = endpoint + "/api/workflow";
|
||||
const apiRoute = endpoint + "/api/upload";
|
||||
// const userId = apiKey
|
||||
try {
|
||||
const body = {
|
||||
workflow_name,
|
||||
workflow_id,
|
||||
workflow: prompt.workflow,
|
||||
workflow_api: prompt.output,
|
||||
snapshot: snapshot,
|
||||
dependencies: deps,
|
||||
};
|
||||
console.log(body);
|
||||
let data = await fetch(apiRoute, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(body),
|
||||
body: JSON.stringify({
|
||||
workflow_name,
|
||||
workflow_id,
|
||||
workflow: prompt.workflow,
|
||||
workflow_api: prompt.output,
|
||||
snapshot: snapshot,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + apiKey,
|
||||
@@ -462,8 +214,6 @@ function addButton() {
|
||||
data = await data.json();
|
||||
}
|
||||
|
||||
loadingDialog.close();
|
||||
|
||||
title.textContent = "Done";
|
||||
title.style.color = "green";
|
||||
|
||||
@@ -480,7 +230,6 @@ function addButton() {
|
||||
title.style.color = "white";
|
||||
}, 1000);
|
||||
} catch (e) {
|
||||
loadingDialog.close();
|
||||
app.ui.dialog.show(e);
|
||||
console.error(e);
|
||||
title.textContent = "Error";
|
||||
@@ -526,16 +275,14 @@ export class InfoDialog extends ComfyDialog {
|
||||
this.element.classList.add("comfy-normal-modal");
|
||||
this.element.style.paddingBottom = "20px";
|
||||
}
|
||||
|
||||
button = undefined;
|
||||
|
||||
createButtons() {
|
||||
this.button = $el("button", {
|
||||
type: "button",
|
||||
textContent: "Close",
|
||||
onclick: () => this.close(),
|
||||
});
|
||||
return [this.button];
|
||||
return [
|
||||
$el("button", {
|
||||
type: "button",
|
||||
textContent: "Close",
|
||||
onclick: () => this.close(),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
close() {
|
||||
@@ -554,72 +301,6 @@ export class InfoDialog extends ComfyDialog {
|
||||
this.element.style.display = "flex";
|
||||
this.element.style.zIndex = 1001;
|
||||
}
|
||||
|
||||
showMessage(title, message) {
|
||||
this.show(`
|
||||
<div style="width: 100%; max-width: 600px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||
<h3 style="margin: 0px;">${title}</h3>
|
||||
<label>
|
||||
${message}
|
||||
</label>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
loadingIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><g fill="none" stroke="#888888" stroke-linecap="round" stroke-width="2"><path stroke-dasharray="60" stroke-dashoffset="60" stroke-opacity=".3" d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z"><animate fill="freeze" attributeName="stroke-dashoffset" dur="1.3s" values="60;0"/></path><path stroke-dasharray="15" stroke-dashoffset="15" d="M12 3C16.9706 3 21 7.02944 21 12"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.3s" values="15;0"/><animateTransform attributeName="transform" dur="1.5s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></g></svg>`;
|
||||
|
||||
showLoading(title, message) {
|
||||
this.show(`
|
||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center;">${title} ${this.loadingIcon}</h3>
|
||||
<label>
|
||||
${message}
|
||||
</label>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
export class LoadingDialog extends ComfyDialog {
|
||||
constructor() {
|
||||
super();
|
||||
this.element.classList.add("comfy-normal-modal");
|
||||
// this.element.style.paddingBottom = "20px";
|
||||
}
|
||||
|
||||
createButtons() {
|
||||
return [];
|
||||
}
|
||||
|
||||
close() {
|
||||
this.element.style.display = "none";
|
||||
}
|
||||
|
||||
show(html) {
|
||||
this.textElement.style["white-space"] = "normal";
|
||||
this.textElement.style.color = "white";
|
||||
this.textElement.style.marginTop = "0px";
|
||||
if (typeof html === "string") {
|
||||
this.textElement.innerHTML = html;
|
||||
} else {
|
||||
this.textElement.replaceChildren(html);
|
||||
}
|
||||
this.element.style.display = "flex";
|
||||
this.element.style.zIndex = 1001;
|
||||
}
|
||||
|
||||
loadingIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><g fill="none" stroke="#888888" stroke-linecap="round" stroke-width="2"><path stroke-dasharray="60" stroke-dashoffset="60" stroke-opacity=".3" d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z"><animate fill="freeze" attributeName="stroke-dashoffset" dur="1.3s" values="60;0"/></path><path stroke-dasharray="15" stroke-dashoffset="15" d="M12 3C16.9706 3 21 7.02944 21 12"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.3s" values="15;0"/><animateTransform attributeName="transform" dur="1.5s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></g></svg>`;
|
||||
|
||||
showLoading(title, message) {
|
||||
this.show(`
|
||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${
|
||||
this.loadingIcon
|
||||
}</h3>
|
||||
${message ? `<label>${message}</label>` : ""}
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
export class InputDialog extends InfoDialog {
|
||||
@@ -686,6 +367,7 @@ export class InputDialog extends InfoDialog {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ConfirmDialog extends InfoDialog {
|
||||
callback = undefined;
|
||||
|
||||
@@ -735,7 +417,7 @@ export class ConfirmDialog extends InfoDialog {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.callback = resolve;
|
||||
this.show(`
|
||||
<div style="width: 100%; max-width: 600px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||
<h3 style="margin: 0px;">${title}</h3>
|
||||
<label>
|
||||
${message}
|
||||
@@ -747,15 +429,9 @@ export class ConfirmDialog extends InfoDialog {
|
||||
}
|
||||
|
||||
export const inputDialog = new InputDialog();
|
||||
export const loadingDialog = new LoadingDialog();
|
||||
export const infoDialog = new InfoDialog();
|
||||
export const confirmDialog = new ConfirmDialog();
|
||||
|
||||
/**
|
||||
* Retrieves deployment data from local storage or defaults.
|
||||
* @param {string} [environment] - The environment to get the data for.
|
||||
* @returns {{endpoint: string, apiKey: string, displayName: string, environment?: string}} The deployment data.
|
||||
*/
|
||||
function getData(environment) {
|
||||
const deployOption =
|
||||
environment || localStorage.getItem("comfy_deploy_env") || "cloud";
|
||||
@@ -778,21 +454,8 @@ function getData(environment) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves deployment data from local storage or defaults.
|
||||
* @param {{endpoint: string, apiKey: string, displayName: string, environment?: string}} [data] - The environment to get the data for.
|
||||
*/
|
||||
function saveData(data) {
|
||||
localStorage.setItem(
|
||||
"comfy_deploy_env_data_" + data.environment,
|
||||
JSON.stringify(data),
|
||||
);
|
||||
}
|
||||
|
||||
export class ConfigDialog extends ComfyDialog {
|
||||
container = null;
|
||||
poll = null;
|
||||
timeout = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -835,24 +498,22 @@ export class ConfigDialog extends ComfyDialog {
|
||||
|
||||
close() {
|
||||
this.element.style.display = "none";
|
||||
clearInterval(this.poll);
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
save(api_key, displayName) {
|
||||
if (!displayName) displayName = getData().displayName;
|
||||
|
||||
save() {
|
||||
const deployOption = this.container.querySelector("#deployOption").value;
|
||||
localStorage.setItem("comfy_deploy_env", deployOption);
|
||||
|
||||
const endpoint = this.container.querySelector("#endpoint").value;
|
||||
const apiKey = api_key ?? this.container.querySelector("#apiKey").value;
|
||||
saveData({
|
||||
const apiKey = this.container.querySelector("#apiKey").value;
|
||||
const data = {
|
||||
endpoint,
|
||||
apiKey,
|
||||
displayName,
|
||||
environment: deployOption,
|
||||
});
|
||||
};
|
||||
localStorage.setItem(
|
||||
"comfy_deploy_env_data_" + deployOption,
|
||||
JSON.stringify(data),
|
||||
);
|
||||
this.close();
|
||||
}
|
||||
|
||||
@@ -866,8 +527,12 @@ export class ConfigDialog extends ComfyDialog {
|
||||
<h3 style="margin: 0px;">Comfy Deploy Config</h3>
|
||||
<label style="color: white; width: 100%;">
|
||||
<select id="deployOption" style="margin: 8px 0px; width: 100%; height:30px; box-sizing: border-box;" >
|
||||
<option value="cloud" ${data.environment === "cloud" ? "selected" : ""}>Cloud</option>
|
||||
<option value="local" ${data.environment === "local" ? "selected" : ""}>Local</option>
|
||||
<option value="cloud" ${
|
||||
data.environment === "cloud" ? "selected" : ""
|
||||
}>Cloud</option>
|
||||
<option value="local" ${
|
||||
data.environment === "local" ? "selected" : ""
|
||||
}>Local</option>
|
||||
</select>
|
||||
</label>
|
||||
<label style="color: white; width: 100%;">
|
||||
@@ -877,61 +542,16 @@ export class ConfigDialog extends ComfyDialog {
|
||||
}">
|
||||
</label>
|
||||
<label style="color: white;">
|
||||
API Key: ${data.displayName ?? ""}
|
||||
API Key:
|
||||
<input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${
|
||||
data.apiKey
|
||||
}">
|
||||
<button id="loginButton" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;">
|
||||
${
|
||||
data.apiKey ? "Re-login with ComfyDeploy" : "Login with ComfyDeploy"
|
||||
}
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const button = this.container.querySelector("#loginButton");
|
||||
button.onclick = () => {
|
||||
const uuid =
|
||||
Math.random().toString(36).substring(2, 15) +
|
||||
Math.random().toString(36).substring(2, 15);
|
||||
window.open(data.endpoint + "/auth-request/" + uuid, "_blank");
|
||||
|
||||
this.timeout = setTimeout(() => {
|
||||
clearInterval(poll);
|
||||
infoDialog.showMessage(
|
||||
"Timeout",
|
||||
"Wait too long for the response, please try re-login",
|
||||
);
|
||||
}, 30000); // Stop polling after 30 seconds
|
||||
|
||||
this.poll = setInterval(() => {
|
||||
fetch(data.endpoint + "/api/auth-response/" + uuid)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
if (json.api_key) {
|
||||
this.save(json.api_key, json.name);
|
||||
this.container.querySelector("#apiKey").value = json.api_key;
|
||||
infoDialog.show();
|
||||
clearInterval(this.poll);
|
||||
clearTimeout(this.timeout);
|
||||
infoDialog.showMessage(
|
||||
"Authenticated",
|
||||
"You will be able to upload workflow to " + json.name,
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error);
|
||||
clearInterval(this.poll);
|
||||
clearTimeout(this.timeout);
|
||||
infoDialog.showMessage("Error", error);
|
||||
});
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const apiKeyInput = this.container.querySelector("#apiKey");
|
||||
apiKeyInput.addEventListener("paste", (e) => {
|
||||
apiKeyInput.addEventListener("paste", function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
**/node_modules
|
||||
**/.next
|
||||
**/public
|
||||
packages/prisma/zod
|
||||
apps/web/public/embed
|
||||
@@ -0,0 +1,95 @@
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
// "plugin:playwright/playwright-test",
|
||||
"next",
|
||||
// "next/core-web-vitals",
|
||||
"plugin:prettier/recommended",
|
||||
// "turbo",
|
||||
// "plugin:you-dont-need-lodash-underscore/compatible-warn",
|
||||
],
|
||||
plugins: ["unused-imports"],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ["./tsconfig.json"],
|
||||
// project: ["./apps/*/tsconfig.json", "./packages/*/tsconfig.json"],
|
||||
},
|
||||
settings: {
|
||||
next: {
|
||||
// rootDir: ["apps/*/", "packages/*/"],
|
||||
rootDir: ["src"],
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"@next/next/no-img-element": "off",
|
||||
"@next/next/no-html-link-for-pages": "off",
|
||||
"jsx-a11y/role-supports-aria-props": "off", // @see https://github.com/vercel/next.js/issues/27989#issuecomment-897638654
|
||||
// "playwright/no-page-pause": "error",
|
||||
"react/jsx-curly-brace-presence": [
|
||||
"error",
|
||||
{ props: "never", children: "never" },
|
||||
],
|
||||
"react/self-closing-comp": ["error", { component: true, html: true }],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
vars: "all",
|
||||
varsIgnorePattern: "^_",
|
||||
args: "after-used",
|
||||
argsIgnorePattern: "^_",
|
||||
destructuredArrayIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
patterns: ["lodash"],
|
||||
},
|
||||
],
|
||||
"prefer-template": "error",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.ts", "*.tsx"],
|
||||
extends: [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
// "plugin:@calcom/eslint/recommended",
|
||||
],
|
||||
plugins: [
|
||||
"@typescript-eslint",
|
||||
// "@calcom/eslint"
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
rules: {
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{
|
||||
prefer: "type-imports",
|
||||
// TODO: enable this once prettier supports it
|
||||
// fixStyle: "inline-type-imports",
|
||||
fixStyle: "separate-type-imports",
|
||||
disallowTypeAnnotations: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
// overrides: [
|
||||
// {
|
||||
// files: ["**/playwright/**/*.{tsx,ts}"],
|
||||
// rules: {
|
||||
// "@typescript-eslint/no-unused-vars": "off",
|
||||
// "no-undef": "off",
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
},
|
||||
// {
|
||||
// files: ["**/playwright/**/*.{js,jsx}"],
|
||||
// rules: {
|
||||
// "@typescript-eslint/no-unused-vars": "off",
|
||||
// "no-undef": "off",
|
||||
// },
|
||||
// },
|
||||
],
|
||||
};
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "started_at" timestamp;
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "share_slug" text;--> statement-breakpoint
|
||||
ALTER TABLE "comfyui_deploy"."deployments" ADD CONSTRAINT "deployments_share_slug_unique" UNIQUE("share_slug");
|
||||
@@ -1,8 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."auth_requests" (
|
||||
"request_id" text PRIMARY KEY NOT NULL,
|
||||
"user_id" text,
|
||||
"org_id" text,
|
||||
"api_hash" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE "comfyui_deploy"."auth_requests" ADD COLUMN "expired_date" timestamp;
|
||||
@@ -1,762 +0,0 @@
|
||||
{
|
||||
"id": "1ca4fdb7-c0c4-4c39-8b47-f40282293da0",
|
||||
"prevId": "db06ea66-92c2-4ebe-93c1-6cb8a90ccd8b",
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"tables": {
|
||||
"api_keys": {
|
||||
"name": "api_keys",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"key": {
|
||||
"name": "key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"revoked": {
|
||||
"name": "revoked",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"api_keys_user_id_users_id_fk": {
|
||||
"name": "api_keys_user_id_users_id_fk",
|
||||
"tableFrom": "api_keys",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"api_keys_key_unique": {
|
||||
"name": "api_keys_key_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"deployments": {
|
||||
"name": "deployments",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"showcase_media": {
|
||||
"name": "showcase_media",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"environment": {
|
||||
"name": "environment",
|
||||
"type": "deployment_environment",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"deployments_user_id_users_id_fk": {
|
||||
"name": "deployments_user_id_users_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_id_workflows_id_fk": {
|
||||
"name": "deployments_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_machine_id_machines_id_fk": {
|
||||
"name": "deployments_machine_id_machines_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"machines": {
|
||||
"name": "machines",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"endpoint": {
|
||||
"name": "endpoint",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"disabled": {
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"auth_token": {
|
||||
"name": "auth_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "machine_type",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'classic'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "machine_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'ready'"
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"models": {
|
||||
"name": "models",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"gpu": {
|
||||
"name": "gpu",
|
||||
"type": "machine_gpu",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_machine_instance_id": {
|
||||
"name": "build_machine_instance_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_log": {
|
||||
"name": "build_log",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"machines_user_id_users_id_fk": {
|
||||
"name": "machines_user_id_users_id_fk",
|
||||
"tableFrom": "machines",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_run_outputs": {
|
||||
"name": "workflow_run_outputs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"run_id": {
|
||||
"name": "run_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"data": {
|
||||
"name": "data",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||
"tableFrom": "workflow_run_outputs",
|
||||
"tableTo": "workflow_runs",
|
||||
"columnsFrom": [
|
||||
"run_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_runs": {
|
||||
"name": "workflow_runs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_inputs": {
|
||||
"name": "workflow_inputs",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"origin": {
|
||||
"name": "origin",
|
||||
"type": "workflow_run_origin",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'api'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "workflow_run_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not-started'"
|
||||
},
|
||||
"ended_at": {
|
||||
"name": "ended_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_machine_id_machines_id_fk": {
|
||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflows": {
|
||||
"name": "workflows",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflows_user_id_users_id_fk": {
|
||||
"name": "workflows_user_id_users_id_fk",
|
||||
"tableFrom": "workflows",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_versions": {
|
||||
"name": "workflow_versions",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow": {
|
||||
"name": "workflow",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_api": {
|
||||
"name": "workflow_api",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"version": {
|
||||
"name": "version",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_versions",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"deployment_environment": {
|
||||
"name": "deployment_environment",
|
||||
"values": {
|
||||
"staging": "staging",
|
||||
"production": "production",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"machine_gpu": {
|
||||
"name": "machine_gpu",
|
||||
"values": {
|
||||
"T4": "T4",
|
||||
"A10G": "A10G",
|
||||
"A100": "A100"
|
||||
}
|
||||
},
|
||||
"machine_status": {
|
||||
"name": "machine_status",
|
||||
"values": {
|
||||
"ready": "ready",
|
||||
"building": "building",
|
||||
"error": "error"
|
||||
}
|
||||
},
|
||||
"machine_type": {
|
||||
"name": "machine_type",
|
||||
"values": {
|
||||
"classic": "classic",
|
||||
"runpod-serverless": "runpod-serverless",
|
||||
"modal-serverless": "modal-serverless",
|
||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
||||
}
|
||||
},
|
||||
"workflow_run_origin": {
|
||||
"name": "workflow_run_origin",
|
||||
"values": {
|
||||
"manual": "manual",
|
||||
"api": "api",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"workflow_run_status": {
|
||||
"name": "workflow_run_status",
|
||||
"values": {
|
||||
"not-started": "not-started",
|
||||
"running": "running",
|
||||
"uploading": "uploading",
|
||||
"success": "success",
|
||||
"failed": "failed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"comfyui_deploy": "comfyui_deploy"
|
||||
},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
}
|
||||
}
|
||||
@@ -1,776 +0,0 @@
|
||||
{
|
||||
"id": "1425ee00-66fb-4541-8da7-19b217944545",
|
||||
"prevId": "1ca4fdb7-c0c4-4c39-8b47-f40282293da0",
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"tables": {
|
||||
"api_keys": {
|
||||
"name": "api_keys",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"key": {
|
||||
"name": "key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"revoked": {
|
||||
"name": "revoked",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"api_keys_user_id_users_id_fk": {
|
||||
"name": "api_keys_user_id_users_id_fk",
|
||||
"tableFrom": "api_keys",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"api_keys_key_unique": {
|
||||
"name": "api_keys_key_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"deployments": {
|
||||
"name": "deployments",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"share_slug": {
|
||||
"name": "share_slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"showcase_media": {
|
||||
"name": "showcase_media",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"environment": {
|
||||
"name": "environment",
|
||||
"type": "deployment_environment",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"deployments_user_id_users_id_fk": {
|
||||
"name": "deployments_user_id_users_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_id_workflows_id_fk": {
|
||||
"name": "deployments_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_machine_id_machines_id_fk": {
|
||||
"name": "deployments_machine_id_machines_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"deployments_share_slug_unique": {
|
||||
"name": "deployments_share_slug_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"share_slug"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"machines": {
|
||||
"name": "machines",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"endpoint": {
|
||||
"name": "endpoint",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"disabled": {
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"auth_token": {
|
||||
"name": "auth_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "machine_type",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'classic'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "machine_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'ready'"
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"models": {
|
||||
"name": "models",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"gpu": {
|
||||
"name": "gpu",
|
||||
"type": "machine_gpu",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_machine_instance_id": {
|
||||
"name": "build_machine_instance_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_log": {
|
||||
"name": "build_log",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"machines_user_id_users_id_fk": {
|
||||
"name": "machines_user_id_users_id_fk",
|
||||
"tableFrom": "machines",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_run_outputs": {
|
||||
"name": "workflow_run_outputs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"run_id": {
|
||||
"name": "run_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"data": {
|
||||
"name": "data",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||
"tableFrom": "workflow_run_outputs",
|
||||
"tableTo": "workflow_runs",
|
||||
"columnsFrom": [
|
||||
"run_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_runs": {
|
||||
"name": "workflow_runs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_inputs": {
|
||||
"name": "workflow_inputs",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"origin": {
|
||||
"name": "origin",
|
||||
"type": "workflow_run_origin",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'api'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "workflow_run_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not-started'"
|
||||
},
|
||||
"ended_at": {
|
||||
"name": "ended_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_machine_id_machines_id_fk": {
|
||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflows": {
|
||||
"name": "workflows",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflows_user_id_users_id_fk": {
|
||||
"name": "workflows_user_id_users_id_fk",
|
||||
"tableFrom": "workflows",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_versions": {
|
||||
"name": "workflow_versions",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow": {
|
||||
"name": "workflow",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_api": {
|
||||
"name": "workflow_api",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"version": {
|
||||
"name": "version",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_versions",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"deployment_environment": {
|
||||
"name": "deployment_environment",
|
||||
"values": {
|
||||
"staging": "staging",
|
||||
"production": "production",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"machine_gpu": {
|
||||
"name": "machine_gpu",
|
||||
"values": {
|
||||
"T4": "T4",
|
||||
"A10G": "A10G",
|
||||
"A100": "A100"
|
||||
}
|
||||
},
|
||||
"machine_status": {
|
||||
"name": "machine_status",
|
||||
"values": {
|
||||
"ready": "ready",
|
||||
"building": "building",
|
||||
"error": "error"
|
||||
}
|
||||
},
|
||||
"machine_type": {
|
||||
"name": "machine_type",
|
||||
"values": {
|
||||
"classic": "classic",
|
||||
"runpod-serverless": "runpod-serverless",
|
||||
"modal-serverless": "modal-serverless",
|
||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
||||
}
|
||||
},
|
||||
"workflow_run_origin": {
|
||||
"name": "workflow_run_origin",
|
||||
"values": {
|
||||
"manual": "manual",
|
||||
"api": "api",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"workflow_run_status": {
|
||||
"name": "workflow_run_status",
|
||||
"values": {
|
||||
"not-started": "not-started",
|
||||
"running": "running",
|
||||
"uploading": "uploading",
|
||||
"success": "success",
|
||||
"failed": "failed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"comfyui_deploy": "comfyui_deploy"
|
||||
},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
}
|
||||
}
|
||||
@@ -1,824 +0,0 @@
|
||||
{
|
||||
"id": "97662b25-3992-4859-9bdc-560e2a70daea",
|
||||
"prevId": "1425ee00-66fb-4541-8da7-19b217944545",
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"tables": {
|
||||
"api_keys": {
|
||||
"name": "api_keys",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"key": {
|
||||
"name": "key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"revoked": {
|
||||
"name": "revoked",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"api_keys_user_id_users_id_fk": {
|
||||
"name": "api_keys_user_id_users_id_fk",
|
||||
"tableFrom": "api_keys",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"api_keys_key_unique": {
|
||||
"name": "api_keys_key_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_requests": {
|
||||
"name": "auth_requests",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"request_id": {
|
||||
"name": "request_id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"api_hash": {
|
||||
"name": "api_hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"deployments": {
|
||||
"name": "deployments",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"share_slug": {
|
||||
"name": "share_slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"showcase_media": {
|
||||
"name": "showcase_media",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"environment": {
|
||||
"name": "environment",
|
||||
"type": "deployment_environment",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"deployments_user_id_users_id_fk": {
|
||||
"name": "deployments_user_id_users_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_id_workflows_id_fk": {
|
||||
"name": "deployments_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_machine_id_machines_id_fk": {
|
||||
"name": "deployments_machine_id_machines_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"deployments_share_slug_unique": {
|
||||
"name": "deployments_share_slug_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"share_slug"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"machines": {
|
||||
"name": "machines",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"endpoint": {
|
||||
"name": "endpoint",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"disabled": {
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"auth_token": {
|
||||
"name": "auth_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "machine_type",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'classic'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "machine_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'ready'"
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"models": {
|
||||
"name": "models",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"gpu": {
|
||||
"name": "gpu",
|
||||
"type": "machine_gpu",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_machine_instance_id": {
|
||||
"name": "build_machine_instance_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_log": {
|
||||
"name": "build_log",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"machines_user_id_users_id_fk": {
|
||||
"name": "machines_user_id_users_id_fk",
|
||||
"tableFrom": "machines",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_run_outputs": {
|
||||
"name": "workflow_run_outputs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"run_id": {
|
||||
"name": "run_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"data": {
|
||||
"name": "data",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||
"tableFrom": "workflow_run_outputs",
|
||||
"tableTo": "workflow_runs",
|
||||
"columnsFrom": [
|
||||
"run_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_runs": {
|
||||
"name": "workflow_runs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_inputs": {
|
||||
"name": "workflow_inputs",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"origin": {
|
||||
"name": "origin",
|
||||
"type": "workflow_run_origin",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'api'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "workflow_run_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not-started'"
|
||||
},
|
||||
"ended_at": {
|
||||
"name": "ended_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_machine_id_machines_id_fk": {
|
||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflows": {
|
||||
"name": "workflows",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflows_user_id_users_id_fk": {
|
||||
"name": "workflows_user_id_users_id_fk",
|
||||
"tableFrom": "workflows",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_versions": {
|
||||
"name": "workflow_versions",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow": {
|
||||
"name": "workflow",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_api": {
|
||||
"name": "workflow_api",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"version": {
|
||||
"name": "version",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_versions",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"deployment_environment": {
|
||||
"name": "deployment_environment",
|
||||
"values": {
|
||||
"staging": "staging",
|
||||
"production": "production",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"machine_gpu": {
|
||||
"name": "machine_gpu",
|
||||
"values": {
|
||||
"T4": "T4",
|
||||
"A10G": "A10G",
|
||||
"A100": "A100"
|
||||
}
|
||||
},
|
||||
"machine_status": {
|
||||
"name": "machine_status",
|
||||
"values": {
|
||||
"ready": "ready",
|
||||
"building": "building",
|
||||
"error": "error"
|
||||
}
|
||||
},
|
||||
"machine_type": {
|
||||
"name": "machine_type",
|
||||
"values": {
|
||||
"classic": "classic",
|
||||
"runpod-serverless": "runpod-serverless",
|
||||
"modal-serverless": "modal-serverless",
|
||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
||||
}
|
||||
},
|
||||
"workflow_run_origin": {
|
||||
"name": "workflow_run_origin",
|
||||
"values": {
|
||||
"manual": "manual",
|
||||
"api": "api",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"workflow_run_status": {
|
||||
"name": "workflow_run_status",
|
||||
"values": {
|
||||
"not-started": "not-started",
|
||||
"running": "running",
|
||||
"uploading": "uploading",
|
||||
"success": "success",
|
||||
"failed": "failed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"comfyui_deploy": "comfyui_deploy"
|
||||
},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
}
|
||||
}
|
||||
@@ -1,830 +0,0 @@
|
||||
{
|
||||
"id": "8d654f92-7f7e-420f-bbd3-73b6b27adf35",
|
||||
"prevId": "97662b25-3992-4859-9bdc-560e2a70daea",
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"tables": {
|
||||
"api_keys": {
|
||||
"name": "api_keys",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"key": {
|
||||
"name": "key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"revoked": {
|
||||
"name": "revoked",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"api_keys_user_id_users_id_fk": {
|
||||
"name": "api_keys_user_id_users_id_fk",
|
||||
"tableFrom": "api_keys",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"api_keys_key_unique": {
|
||||
"name": "api_keys_key_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_requests": {
|
||||
"name": "auth_requests",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"request_id": {
|
||||
"name": "request_id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"api_hash": {
|
||||
"name": "api_hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"expired_date": {
|
||||
"name": "expired_date",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"deployments": {
|
||||
"name": "deployments",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"share_slug": {
|
||||
"name": "share_slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"showcase_media": {
|
||||
"name": "showcase_media",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"environment": {
|
||||
"name": "environment",
|
||||
"type": "deployment_environment",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"deployments_user_id_users_id_fk": {
|
||||
"name": "deployments_user_id_users_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_workflow_id_workflows_id_fk": {
|
||||
"name": "deployments_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"deployments_machine_id_machines_id_fk": {
|
||||
"name": "deployments_machine_id_machines_id_fk",
|
||||
"tableFrom": "deployments",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"deployments_share_slug_unique": {
|
||||
"name": "deployments_share_slug_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"share_slug"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"machines": {
|
||||
"name": "machines",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"endpoint": {
|
||||
"name": "endpoint",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"disabled": {
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"auth_token": {
|
||||
"name": "auth_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "machine_type",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'classic'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "machine_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'ready'"
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"models": {
|
||||
"name": "models",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"gpu": {
|
||||
"name": "gpu",
|
||||
"type": "machine_gpu",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_machine_instance_id": {
|
||||
"name": "build_machine_instance_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"build_log": {
|
||||
"name": "build_log",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"machines_user_id_users_id_fk": {
|
||||
"name": "machines_user_id_users_id_fk",
|
||||
"tableFrom": "machines",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_run_outputs": {
|
||||
"name": "workflow_run_outputs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"run_id": {
|
||||
"name": "run_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"data": {
|
||||
"name": "data",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||
"tableFrom": "workflow_run_outputs",
|
||||
"tableTo": "workflow_runs",
|
||||
"columnsFrom": [
|
||||
"run_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_runs": {
|
||||
"name": "workflow_runs",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow_version_id": {
|
||||
"name": "workflow_version_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_inputs": {
|
||||
"name": "workflow_inputs",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"machine_id": {
|
||||
"name": "machine_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"origin": {
|
||||
"name": "origin",
|
||||
"type": "workflow_run_origin",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'api'"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "workflow_run_status",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not-started'"
|
||||
},
|
||||
"ended_at": {
|
||||
"name": "ended_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflow_versions",
|
||||
"columnsFrom": [
|
||||
"workflow_version_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"workflow_runs_machine_id_machines_id_fk": {
|
||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
||||
"tableFrom": "workflow_runs",
|
||||
"tableTo": "machines",
|
||||
"columnsFrom": [
|
||||
"machine_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflows": {
|
||||
"name": "workflows",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"org_id": {
|
||||
"name": "org_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflows_user_id_users_id_fk": {
|
||||
"name": "workflows_user_id_users_id_fk",
|
||||
"tableFrom": "workflows",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"workflow_versions": {
|
||||
"name": "workflow_versions",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"workflow_id": {
|
||||
"name": "workflow_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"workflow": {
|
||||
"name": "workflow",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"workflow_api": {
|
||||
"name": "workflow_api",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"version": {
|
||||
"name": "version",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"snapshot": {
|
||||
"name": "snapshot",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
||||
"tableFrom": "workflow_versions",
|
||||
"tableTo": "workflows",
|
||||
"columnsFrom": [
|
||||
"workflow_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"deployment_environment": {
|
||||
"name": "deployment_environment",
|
||||
"values": {
|
||||
"staging": "staging",
|
||||
"production": "production",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"machine_gpu": {
|
||||
"name": "machine_gpu",
|
||||
"values": {
|
||||
"T4": "T4",
|
||||
"A10G": "A10G",
|
||||
"A100": "A100"
|
||||
}
|
||||
},
|
||||
"machine_status": {
|
||||
"name": "machine_status",
|
||||
"values": {
|
||||
"ready": "ready",
|
||||
"building": "building",
|
||||
"error": "error"
|
||||
}
|
||||
},
|
||||
"machine_type": {
|
||||
"name": "machine_type",
|
||||
"values": {
|
||||
"classic": "classic",
|
||||
"runpod-serverless": "runpod-serverless",
|
||||
"modal-serverless": "modal-serverless",
|
||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
||||
}
|
||||
},
|
||||
"workflow_run_origin": {
|
||||
"name": "workflow_run_origin",
|
||||
"values": {
|
||||
"manual": "manual",
|
||||
"api": "api",
|
||||
"public-share": "public-share"
|
||||
}
|
||||
},
|
||||
"workflow_run_status": {
|
||||
"name": "workflow_run_status",
|
||||
"values": {
|
||||
"not-started": "not-started",
|
||||
"running": "running",
|
||||
"uploading": "uploading",
|
||||
"success": "success",
|
||||
"failed": "failed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"comfyui_deploy": "comfyui_deploy"
|
||||
},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
}
|
||||
}
|
||||
@@ -218,34 +218,6 @@
|
||||
"when": 1705716303820,
|
||||
"tag": "0030_kind_doorman",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 31,
|
||||
"version": "5",
|
||||
"when": 1705763980972,
|
||||
"tag": "0031_fast_lyja",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 32,
|
||||
"version": "5",
|
||||
"when": 1705806921697,
|
||||
"tag": "0032_shallow_vermin",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 33,
|
||||
"version": "5",
|
||||
"when": 1705853314500,
|
||||
"tag": "0033_awesome_human_fly",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 34,
|
||||
"version": "5",
|
||||
"when": 1705902960991,
|
||||
"tag": "0034_even_lady_ursula",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+7
-12
@@ -12,31 +12,26 @@ let sslMode: string | boolean = process.env.SSL || "require";
|
||||
|
||||
if (sslMode === "false") sslMode = false;
|
||||
|
||||
let connectionString = process.env.POSTGRES_URL!;
|
||||
|
||||
const isDevContainer = process.env.REMOTE_CONTAINERS !== undefined;
|
||||
if (isDevContainer)
|
||||
connectionString = connectionString.replace(
|
||||
"localhost",
|
||||
"host.docker.internal",
|
||||
);
|
||||
console.log(migrationsFolderName, sslMode);
|
||||
|
||||
const connectionString = process.env.POSTGRES_URL!;
|
||||
console.log(connectionString);
|
||||
const sql = postgres(connectionString, { max: 1, ssl: sslMode as any });
|
||||
const db = drizzle(sql, {
|
||||
logger: true,
|
||||
});
|
||||
|
||||
let retries = 5;
|
||||
while (retries) {
|
||||
while(retries) {
|
||||
try {
|
||||
await sql`SELECT NOW()`;
|
||||
console.log("Database is live");
|
||||
console.log('Database is live');
|
||||
break;
|
||||
} catch (error) {
|
||||
console.error("Database is not live yet", error);
|
||||
console.error('Database is not live yet', error);
|
||||
retries -= 1;
|
||||
console.log(`Retries left: ${retries}`);
|
||||
await new Promise((res) => setTimeout(res, 1000));
|
||||
await new Promise(res => setTimeout(res, 1000));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -1,3 +1,4 @@
|
||||
import million from 'million/compiler';
|
||||
import { recmaPlugins } from "./src/mdx/recma.mjs";
|
||||
import { rehypePlugins } from "./src/mdx/rehype.mjs";
|
||||
import { remarkPlugins } from "./src/mdx/remark.mjs";
|
||||
@@ -20,8 +21,6 @@ const nextConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
export default withSearch(withMDX(nextConfig));
|
||||
|
||||
// export default million.next(
|
||||
// withSearch(withMDX(nextConfig)), { auto: { rsc: true } }
|
||||
// );
|
||||
export default million.next(
|
||||
withSearch(withMDX(nextConfig)), { auto: { rsc: true } }
|
||||
);
|
||||
|
||||
+11
-4
@@ -12,8 +12,7 @@
|
||||
"migrate-production": "bun run migrate.mts",
|
||||
"migrate-local": "SSL=false LOCAL=true bun run migrate.mts",
|
||||
"db-up": "docker-compose up",
|
||||
"db-dev": "bun run db-up && bun run migrate-local",
|
||||
"lint:fix": "bunx @biomejs/biome lint --apply ./src"
|
||||
"db-dev": "bun run db-up && bun run migrate-local"
|
||||
},
|
||||
"dependencies": {
|
||||
"@algolia/autocomplete-core": "^1.13.0",
|
||||
@@ -72,7 +71,6 @@
|
||||
"mdx-annotations": "^0.1.4",
|
||||
"million": "latest",
|
||||
"mitata": "^0.1.6",
|
||||
"ms": "^2.1.3",
|
||||
"nanoid": "^5.0.4",
|
||||
"next": "14.1",
|
||||
"next-plausible": "^3.12.0",
|
||||
@@ -107,17 +105,26 @@
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.5.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "4.1.1",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||
"@typescript-eslint/parser": "^6.13.2",
|
||||
"autoprefixer": "^10.0.1",
|
||||
"concurrently": "^8.2.2",
|
||||
"dotenv": "^16.3.1",
|
||||
"drizzle-kit": "^0.20.6",
|
||||
"eslint": "8.34.0",
|
||||
"eslint-config-next": "^14.0.4",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-config-turbo": "latest",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"postcss": "^8",
|
||||
"postgres": "^3.4.3",
|
||||
"prettier": "2.8.6",
|
||||
"prettier-plugin-tailwindcss": "0.2.5",
|
||||
"sharp": "^0.33.1",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"typescript": "^5"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
@@ -1,3 +1,4 @@
|
||||
import { app } from "../../../../routes/app";
|
||||
import { registerCreateRunRoute } from "@/routes/registerCreateRunRoute";
|
||||
import { registerGetOutputRoute } from "@/routes/registerGetOutputRoute";
|
||||
import { registerUploadRoute } from "@/routes/registerUploadRoute";
|
||||
@@ -5,11 +6,7 @@ import { isKeyRevoked } from "@/server/curdApiKeys";
|
||||
import { parseJWT } from "@/server/parseJWT";
|
||||
import type { Context, Next } from "hono";
|
||||
import { handle } from "hono/vercel";
|
||||
import { app } from "../../../../routes/app";
|
||||
import { registerWorkflowUploadRoute } from "@/routes/registerWorkflowUploadRoute";
|
||||
import { registerGetAuthResponse } from "@/routes/registerGetAuthResponse";
|
||||
import { registerGetWorkflowRoute } from "@/routes/registerGetWorkflow";
|
||||
import { cors } from "hono/cors";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const maxDuration = 300; // 5 minutes
|
||||
|
||||
@@ -19,24 +16,14 @@ declare module "hono" {
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAuth(c: Context, next: Next, headers?: HeadersInit) {
|
||||
async function checkAuth(c: Context, next: Next) {
|
||||
const token = c.req.raw.headers.get("Authorization")?.split(" ")?.[1]; // Assuming token is sent as "Bearer your_token"
|
||||
const userData = token ? parseJWT(token) : undefined;
|
||||
if (!userData || token === undefined) {
|
||||
return c.text("Invalid or expired token", {
|
||||
status: 401,
|
||||
headers: headers,
|
||||
});
|
||||
}
|
||||
|
||||
// If the key has expiration, this is a temporary key and not in our db, so we can skip checking
|
||||
if (userData.exp === undefined) {
|
||||
return c.text("Invalid or expired token", 401);
|
||||
} else {
|
||||
const revokedKey = await isKeyRevoked(token);
|
||||
if (revokedKey)
|
||||
return c.text("Revoked token", {
|
||||
status: 401,
|
||||
headers: headers,
|
||||
});
|
||||
if (revokedKey) return c.text("Revoked token", 401);
|
||||
}
|
||||
|
||||
c.set("apiKeyTokenData", userData);
|
||||
@@ -44,35 +31,18 @@ async function checkAuth(c: Context, next: Next, headers?: HeadersInit) {
|
||||
await next();
|
||||
}
|
||||
|
||||
app.use("/run", checkAuth);
|
||||
app.use("/upload-url", checkAuth);
|
||||
|
||||
const corsHandler = cors({
|
||||
origin: "*",
|
||||
allowHeaders: ["Authorization", "Content-Type"],
|
||||
allowMethods: ["POST", "GET", "OPTIONS"],
|
||||
exposeHeaders: ["Content-Length"],
|
||||
maxAge: 600,
|
||||
credentials: true,
|
||||
app.use("/run", async (c, next) => {
|
||||
return checkAuth(c, next);
|
||||
});
|
||||
|
||||
// CORS Check
|
||||
app.use("/workflow", corsHandler, checkAuth);
|
||||
app.use("/workflow-version/*", corsHandler, checkAuth);
|
||||
app.use("/upload-url", async (c, next) => {
|
||||
return checkAuth(c, next);
|
||||
});
|
||||
|
||||
// create run endpoint
|
||||
registerCreateRunRoute(app);
|
||||
registerGetOutputRoute(app);
|
||||
|
||||
// file upload endpoint
|
||||
registerUploadRoute(app);
|
||||
|
||||
// Anon
|
||||
registerGetAuthResponse(app);
|
||||
|
||||
registerWorkflowUploadRoute(app);
|
||||
registerGetWorkflowRoute(app);
|
||||
|
||||
// The OpenAPI documentation will be available at /doc
|
||||
app.doc("/doc", {
|
||||
openapi: "3.0.0",
|
||||
@@ -99,4 +69,3 @@ const handler = handle(app);
|
||||
|
||||
export const GET = handler;
|
||||
export const POST = handler;
|
||||
export const OPTIONS = handler;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { parseDataSafe } from "../../../../lib/parseDataSafe";
|
||||
import { handleResourceUpload } from "@/server/resource";
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { parseDataSafe } from "../../../../lib/parseDataSafe";
|
||||
|
||||
const Request = z.object({
|
||||
file_name: z.string(),
|
||||
run_id: z.string(),
|
||||
|
||||
type: z.string(),
|
||||
});
|
||||
|
||||
@@ -30,7 +29,7 @@ export async function GET(request: Request) {
|
||||
{
|
||||
url: uploadUrl,
|
||||
},
|
||||
{ status: 200 },
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
@@ -39,7 +38,7 @@ export async function GET(request: Request) {
|
||||
{
|
||||
error: errorMessage,
|
||||
},
|
||||
{ status: 500 },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { snapshotType, workflowAPIType, workflowType } from "@/db/schema";
|
||||
import { createNewWorkflow } from "../../../../server/createNewWorkflow";
|
||||
import { parseJWT } from "../../../../server/parseJWT";
|
||||
import { db } from "@/db/db";
|
||||
import {
|
||||
snapshotType,
|
||||
workflowAPIType,
|
||||
workflowTable,
|
||||
workflowType,
|
||||
workflowVersionTable,
|
||||
} from "@/db/schema";
|
||||
import { parseDataSafe } from "@/lib/parseDataSafe";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
createNewWorkflow,
|
||||
createNewWorkflowVersion,
|
||||
} from "../../../../server/createNewWorkflow";
|
||||
import { parseJWT } from "../../../../server/parseJWT";
|
||||
|
||||
// This is will be deprecated
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
@@ -52,7 +55,7 @@ export async function POST(request: Request) {
|
||||
const [data, error] = await parseDataSafe(
|
||||
UploadRequest,
|
||||
request,
|
||||
corsHeaders,
|
||||
corsHeaders
|
||||
);
|
||||
|
||||
if (!data || error) return error;
|
||||
@@ -72,7 +75,7 @@ export async function POST(request: Request) {
|
||||
|
||||
// Case 1 new workflow
|
||||
try {
|
||||
if ((!workflow_id || workflow_id.length === 0) && workflow_name) {
|
||||
if ((!workflow_id || workflow_id.length == 0) && workflow_name) {
|
||||
// Create a new parent workflow
|
||||
const { workflow_id: _workflow_id, version: _version } =
|
||||
await createNewWorkflow({
|
||||
@@ -88,17 +91,56 @@ export async function POST(request: Request) {
|
||||
|
||||
workflow_id = _workflow_id;
|
||||
version = _version;
|
||||
|
||||
// const workflow_parent = await db
|
||||
// .insert(workflowTable)
|
||||
// .values({
|
||||
// user_id,
|
||||
// name: workflow_name,
|
||||
// org_id: org_id,
|
||||
// })
|
||||
// .returning();
|
||||
|
||||
// workflow_id = workflow_parent[0].id;
|
||||
|
||||
// // Create a new version
|
||||
// const data = await db
|
||||
// .insert(workflowVersionTable)
|
||||
// .values({
|
||||
// workflow_id: workflow_id,
|
||||
// workflow,
|
||||
// workflow_api,
|
||||
// version: 1,
|
||||
// snapshot: snapshot,
|
||||
// })
|
||||
// .returning();
|
||||
// version = data[0].version;
|
||||
} else if (workflow_id) {
|
||||
// Case 2 update workflow
|
||||
const { version: _version } = await createNewWorkflowVersion({
|
||||
workflow_id: workflow_id,
|
||||
workflowData: {
|
||||
workflow,
|
||||
const data = await db
|
||||
.insert(workflowVersionTable)
|
||||
.values({
|
||||
workflow_id,
|
||||
workflow: workflow,
|
||||
workflow_api,
|
||||
snapshot,
|
||||
},
|
||||
});
|
||||
version = _version;
|
||||
// version: sql`${workflowVersionTable.version} + 1`,
|
||||
snapshot: snapshot,
|
||||
version: sql`(
|
||||
SELECT COALESCE(MAX(version), 0) + 1
|
||||
FROM ${workflowVersionTable}
|
||||
WHERE workflow_id = ${workflow_id}
|
||||
)`,
|
||||
})
|
||||
.returning();
|
||||
version = data[0].version;
|
||||
|
||||
await db
|
||||
.update(workflowTable)
|
||||
.set({
|
||||
updated_at: new Date(),
|
||||
})
|
||||
.where(eq(workflowTable.id, workflow_id))
|
||||
.returning();
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{
|
||||
@@ -108,7 +150,7 @@ export async function POST(request: Request) {
|
||||
status: 500,
|
||||
statusText: "Invalid request",
|
||||
headers: corsHeaders,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -120,7 +162,7 @@ export async function POST(request: Request) {
|
||||
status: 500,
|
||||
statusText: "Invalid request",
|
||||
headers: corsHeaders,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -132,6 +174,6 @@ export async function POST(request: Request) {
|
||||
{
|
||||
status: 200,
|
||||
headers: corsHeaders,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import { ButtonAction } from "@/components/ButtonActionLoader";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { createAuthRequest } from "@/server/curdApiKeys";
|
||||
import { auth } from "@clerk/nextjs";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getOrgOrUserDisplayName } from "../../../../server/getOrgOrUserDisplayName";
|
||||
import { db } from "@/db/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { authRequestsTable } from "@/db/schema";
|
||||
|
||||
export default async function Home({
|
||||
params,
|
||||
}: {
|
||||
params: { request_id: string };
|
||||
}) {
|
||||
const { userId, orgId } = await auth();
|
||||
|
||||
if (!userId) redirect("/");
|
||||
|
||||
if (!params.request_id)
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col gap-2 items-center justify-center">
|
||||
No valid request_id
|
||||
</div>
|
||||
);
|
||||
|
||||
const existingResult = await db.query.authRequestsTable.findFirst({
|
||||
where: eq(authRequestsTable.request_id, params.request_id),
|
||||
});
|
||||
|
||||
if (existingResult?.api_hash) {
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col gap-2 items-center justify-center">
|
||||
Request already consumed.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const userName = await getOrgOrUserDisplayName(orgId, userId);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col gap-2 items-center justify-center">
|
||||
<div className="text-lg">Grant API Access to {userName}</div>
|
||||
<Button asChild>
|
||||
<ButtonAction
|
||||
routerAction="do-nothing"
|
||||
action={createAuthRequest.bind(null, params.request_id)}
|
||||
>
|
||||
Grant Access
|
||||
</ButtonAction>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export default function Loading() {
|
||||
const pathName = usePathname();
|
||||
return <LoadingPageWrapper className="h-full" tag={pathName.toLowerCase()} />;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Page() {
|
||||
return <Examples />;
|
||||
}
|
||||
|
||||
|
||||
type exampleWorkflow = {
|
||||
title: string;
|
||||
description: string;
|
||||
previewURL: string;
|
||||
image: {
|
||||
src: string,
|
||||
alt: string,
|
||||
};
|
||||
};
|
||||
|
||||
const exampleWorkflows: exampleWorkflow[] = [
|
||||
{
|
||||
title: "Txt2Img SDXL",
|
||||
description: "The basic workflow, type a prompt and generate images based on that.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-txt2img-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/txt2img.webp',
|
||||
alt: 'IPAdapter workflow',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Txt2Img LCM SDXL",
|
||||
description: "Images in a couple of seconds, increase the speed of each generation using LCM Lora.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-lcm-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/txt2img-lcm.webp',
|
||||
alt: 'txt2img LCM SDXL',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "IPAdapter SDXL",
|
||||
description: "Load images and use them as reference for new generations.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-ip-adapter-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/ipadapter.webp',
|
||||
alt: 'IPAdapter workflow',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Upscale and Add Detail SDXL",
|
||||
description: "Upscale and Add Details to your creations",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-upscale-and-add-detail-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/upscale.webp',
|
||||
alt: 'Upscale and Add Detail SDXL',
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
async function Examples() {
|
||||
return (
|
||||
<div className="w-full py-4">
|
||||
<section className="mx-auto flex max-w-[980px] flex-col items-center gap-2 py-8 md:py-12 md:pb-8 lg:py-24 lg:pb-20">
|
||||
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-center">
|
||||
Check out some examples
|
||||
</h1>
|
||||
<p className="max-w-[560px] text-center text-lg text-muted-foreground">Text to Image, Image to Image, IPAdapter, and more. Here are some examples that you can use to deploy your workflow.</p>
|
||||
</section>
|
||||
<section className="flex justify-center flex-wrap gap-4">
|
||||
{exampleWorkflows.map(workflow => {
|
||||
return <Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>{workflow.title}</CardTitle>
|
||||
<CardDescription>{workflow.description}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Image src={workflow.image.src} alt={workflow.image.alt} width={350} height={230} />
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-end gap-2">
|
||||
<Button asChild>
|
||||
<Link href={workflow.previewURL}>View Workflow</Link>
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>;
|
||||
})}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Navbar } from "../../components/Navbar";
|
||||
import "./globals.css";
|
||||
import { PHProvider } from "./providers";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { ClerkProvider } from "@clerk/nextjs";
|
||||
import type { Metadata } from "next";
|
||||
import meta from "next-gen/config";
|
||||
import PlausibleProvider from "next-plausible";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Inter } from "next/font/google";
|
||||
import { Toaster } from "sonner";
|
||||
import { PHProvider } from "./providers";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
const PostHogPageView = dynamic(() => import("./PostHogPageView"), {
|
||||
ssr: false,
|
||||
|
||||
@@ -2,11 +2,11 @@ import { ButtonActionMenu } from "@/components/ButtonActionLoader";
|
||||
import { RunWorkflowInline } from "@/components/RunWorkflowInline";
|
||||
import { PublicRunOutputs } from "@/components/VersionSelect";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { db } from "@/db/db";
|
||||
import { usersTable } from "@/db/schema";
|
||||
@@ -14,9 +14,9 @@ import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
|
||||
import { getRelativeTime } from "@/lib/getRelativeTime";
|
||||
import { setInitialUserData } from "@/lib/setInitialUserData";
|
||||
import {
|
||||
cloneMachine,
|
||||
cloneWorkflow,
|
||||
findSharedDeployment,
|
||||
cloneMachine,
|
||||
cloneWorkflow,
|
||||
findSharedDeployment,
|
||||
} from "@/server/curdDeploments";
|
||||
import { auth, clerkClient } from "@clerk/nextjs/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
@@ -25,87 +25,89 @@ import { redirect } from "next/navigation";
|
||||
export const maxDuration = 300; // 5 minutes
|
||||
|
||||
export default async function Page({
|
||||
params,
|
||||
params,
|
||||
}: {
|
||||
params: { share_id: string };
|
||||
params: { share_id: string };
|
||||
}) {
|
||||
const { userId } = await auth();
|
||||
const { userId } = await auth();
|
||||
|
||||
// If there is user, check if the user data is present
|
||||
if (userId) {
|
||||
const user = await db.query.usersTable.findFirst({
|
||||
where: eq(usersTable.id, userId),
|
||||
});
|
||||
// If there is user, check if the user data is present
|
||||
if (userId) {
|
||||
const user = await db.query.usersTable.findFirst({
|
||||
where: eq(usersTable.id, userId),
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
await setInitialUserData(userId);
|
||||
}
|
||||
}
|
||||
if (!user) {
|
||||
await setInitialUserData(userId);
|
||||
}
|
||||
}
|
||||
|
||||
const sharedDeployment = await findSharedDeployment(params.share_id);
|
||||
const sharedDeployment = await findSharedDeployment(params.share_id);
|
||||
|
||||
if (!sharedDeployment) return redirect("/");
|
||||
if (!sharedDeployment) return redirect("/");
|
||||
|
||||
const userName = sharedDeployment.workflow.org_id
|
||||
? await clerkClient.organizations
|
||||
.getOrganization({
|
||||
organizationId: sharedDeployment.workflow.org_id,
|
||||
})
|
||||
.then((x) => x.name)
|
||||
: sharedDeployment.user.name;
|
||||
const userName = sharedDeployment.workflow.org_id
|
||||
? await clerkClient.organizations
|
||||
.getOrganization({
|
||||
organizationId: sharedDeployment.workflow.org_id,
|
||||
})
|
||||
.then((x) => x.name)
|
||||
: sharedDeployment.user.name;
|
||||
|
||||
const inputs = getInputsFromWorkflow(sharedDeployment.version);
|
||||
const inputs = getInputsFromWorkflow(sharedDeployment.version);
|
||||
|
||||
return (
|
||||
<div className="mt-4 w-full grid grid-rows-[1fr,1fr] lg:grid-cols-[minmax(auto,500px),1fr] gap-4 max-h-[calc(100dvh-100px)]">
|
||||
<Card className="w-full h-fit mt-4">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex justify-between items-center">
|
||||
<div>
|
||||
{userName}
|
||||
{" / "}
|
||||
{sharedDeployment.workflow.name}
|
||||
</div>
|
||||
return (
|
||||
<div className="mt-4 w-full grid grid-rows-[1fr,1fr] lg:grid-cols-[minmax(auto,500px),1fr] gap-4 max-h-[calc(100dvh-100px)]">
|
||||
<Card className="w-full h-fit mt-4">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex justify-between items-center">
|
||||
<div>
|
||||
{userName}
|
||||
{" / "}
|
||||
{sharedDeployment.workflow.name}
|
||||
</div>
|
||||
|
||||
<ButtonActionMenu
|
||||
title="Clone"
|
||||
actions={[
|
||||
{
|
||||
title: "Workflow",
|
||||
action: cloneWorkflow.bind(null, sharedDeployment.id),
|
||||
},
|
||||
{
|
||||
title: "Machine",
|
||||
action: cloneMachine.bind(null, sharedDeployment.id),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</CardTitle>
|
||||
<CardDescription suppressHydrationWarning={true}>
|
||||
{getRelativeTime(sharedDeployment?.updated_at)}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<ButtonActionMenu
|
||||
title="Clone"
|
||||
actions={[
|
||||
{
|
||||
title: "Workflow",
|
||||
action: cloneWorkflow.bind(null, sharedDeployment.id),
|
||||
},
|
||||
{
|
||||
title: "Machine",
|
||||
action: cloneMachine.bind(null, sharedDeployment.id),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</CardTitle>
|
||||
<CardDescription suppressHydrationWarning={true}>
|
||||
{getRelativeTime(sharedDeployment?.updated_at)}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div>
|
||||
{sharedDeployment?.description && sharedDeployment?.description}
|
||||
</div>
|
||||
<RunWorkflowInline
|
||||
inputs={inputs}
|
||||
machine_id={sharedDeployment.machine_id}
|
||||
workflow_version_id={sharedDeployment.workflow_version_id}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="w-full h-fit mt-4">
|
||||
<CardHeader>
|
||||
<CardDescription>Run outputs</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div>
|
||||
{sharedDeployment?.description && (
|
||||
<>{sharedDeployment?.description}</>
|
||||
)}
|
||||
</div>
|
||||
<RunWorkflowInline
|
||||
inputs={inputs}
|
||||
machine_id={sharedDeployment.machine_id}
|
||||
workflow_version_id={sharedDeployment.workflow_version_id}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="w-full h-fit mt-4">
|
||||
<CardHeader>
|
||||
<CardDescription>Run outputs</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<PublicRunOutputs preview={sharedDeployment.showcase_media} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
<CardContent>
|
||||
<PublicRunOutputs preview={sharedDeployment.showcase_media} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { CreateShareButton } from "@/components/CreateShareButton";
|
||||
import { MachinesWSMain } from "@/components/MachinesWS";
|
||||
import { VersionDetails } from "@/components/VersionDetails";
|
||||
import {
|
||||
CopyWorkflowVersion,
|
||||
CreateDeploymentButton,
|
||||
CreateShareButton,
|
||||
MachineSelect,
|
||||
OpenEditButton,
|
||||
RunWorkflowButton,
|
||||
VersionSelect,
|
||||
ViewWorkflowDetailsButton,
|
||||
@@ -49,7 +48,6 @@ export default async function Page({
|
||||
<CreateShareButton workflow={workflow} machines={machines} />
|
||||
<CopyWorkflowVersion workflow={workflow} />
|
||||
<ViewWorkflowDetailsButton workflow={workflow} />
|
||||
<OpenEditButton workflow={workflow} machines={machines} />
|
||||
</div>
|
||||
|
||||
<VersionDetails workflow={workflow} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { setInitialUserData } from "../../../lib/setInitialUserData";
|
||||
import { getAllUserWorkflow } from "../../../server/crudWorkflow";
|
||||
import { getAllUserWorkflow } from "../../../server/getAllUserWorkflow";
|
||||
import { WorkflowList } from "@/components/WorkflowList";
|
||||
import { db } from "@/db/db";
|
||||
import { usersTable } from "@/db/schema";
|
||||
|
||||
@@ -17,11 +17,9 @@ import { useState } from "react";
|
||||
export function ButtonAction({
|
||||
action,
|
||||
children,
|
||||
routerAction = "back",
|
||||
...rest
|
||||
}: {
|
||||
action: () => Promise<any>;
|
||||
routerAction?: "refresh" | "back" | "do-nothing";
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [pending, setPending] = useState(false);
|
||||
@@ -36,10 +34,7 @@ export function ButtonAction({
|
||||
await callServerPromise(action());
|
||||
setPending(false);
|
||||
|
||||
if (routerAction === "back") {
|
||||
router.back();
|
||||
router.refresh();
|
||||
} else if (routerAction === "refresh") router.refresh();
|
||||
router.refresh();
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
"use client";
|
||||
import { LoadingIcon } from "@/components/LoadingIcon";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { createDeployments } from "@/server/curdDeploments";
|
||||
import type { getMachines } from "@/server/curdMachine";
|
||||
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
|
||||
import { Share } from "lucide-react";
|
||||
import { parseAsInteger, useQueryState } from "next-usequerystate";
|
||||
import { useState } from "react";
|
||||
import { useSelectedMachine } from "./VersionSelect";
|
||||
import { callServerPromise } from "./callServerPromise";
|
||||
|
||||
export function CreateShareButton({
|
||||
workflow,
|
||||
machines,
|
||||
}: {
|
||||
workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>;
|
||||
machines: Awaited<ReturnType<typeof getMachines>>;
|
||||
}) {
|
||||
const [version] = useQueryState("version", {
|
||||
defaultValue: workflow?.versions[0].version ?? 1,
|
||||
...parseAsInteger,
|
||||
});
|
||||
const [machine] = useSelectedMachine(machines);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const workflow_version_id = workflow?.versions.find(
|
||||
(x) => x.version == version,
|
||||
)?.id;
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button className="gap-2" disabled={isLoading} variant="outline">
|
||||
Share {isLoading ? <LoadingIcon /> : <Share size={14} />}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56">
|
||||
<DropdownMenuItem
|
||||
onClick={async () => {
|
||||
if (!workflow_version_id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await callServerPromise(
|
||||
createDeployments(
|
||||
workflow.id,
|
||||
workflow_version_id,
|
||||
machine,
|
||||
"public-share",
|
||||
),
|
||||
);
|
||||
setIsLoading(false);
|
||||
}}
|
||||
>
|
||||
Public
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { DeploymentRow } from "./DeploymentRow";
|
||||
import { CodeBlock } from "@/components/CodeBlock";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -8,11 +9,9 @@ import {
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { TableRow } from "@/components/ui/table";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
|
||||
import type { findAllDeployments } from "@/server/findAllRuns";
|
||||
import { DeploymentRow, SharePageDeploymentRow } from "./DeploymentRow";
|
||||
|
||||
const curlTemplate = `
|
||||
curl --request POST \
|
||||
@@ -91,16 +90,14 @@ export function DeploymentDisplay({
|
||||
}) {
|
||||
const workflowInput = getInputsFromWorkflow(deployment.version);
|
||||
|
||||
if (deployment.environment === "public-share") {
|
||||
return <SharePageDeploymentRow deployment={deployment} />;
|
||||
if (deployment.environment == "public-share") {
|
||||
return <DeploymentRow deployment={deployment} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
||||
<TableRow>
|
||||
<DeploymentRow deployment={deployment} />
|
||||
</TableRow>
|
||||
<DeploymentRow deployment={deployment} />
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-3xl">
|
||||
<DialogHeader>
|
||||
@@ -123,7 +120,6 @@ export function DeploymentDisplay({
|
||||
href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts"
|
||||
className="text-blue-500 hover:underline"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
here
|
||||
</a>
|
||||
@@ -136,7 +132,7 @@ export function DeploymentDisplay({
|
||||
: jsClientSetupTemplate,
|
||||
deployment,
|
||||
domain,
|
||||
workflowInput,
|
||||
workflowInput
|
||||
)}
|
||||
/>
|
||||
Create a run via deployment id
|
||||
@@ -148,7 +144,7 @@ export function DeploymentDisplay({
|
||||
: jsClientCreateRunNoInputsTemplate,
|
||||
deployment,
|
||||
domain,
|
||||
workflowInput,
|
||||
workflowInput
|
||||
)}
|
||||
/>
|
||||
Check the status of the run, and retrieve the outputs
|
||||
@@ -157,7 +153,7 @@ export function DeploymentDisplay({
|
||||
code={formatCode(
|
||||
clientTemplate_checkStatus,
|
||||
deployment,
|
||||
domain,
|
||||
domain
|
||||
)}
|
||||
/>
|
||||
</TabsContent>
|
||||
@@ -195,7 +191,7 @@ function formatCode(
|
||||
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0],
|
||||
domain: string,
|
||||
inputs?: ReturnType<typeof getInputsFromWorkflow>,
|
||||
inputsTabs?: number,
|
||||
inputsTabs?: number
|
||||
) {
|
||||
if (inputs && inputs.length > 0) {
|
||||
codeTemplate = codeTemplate.replace(
|
||||
@@ -204,20 +200,20 @@ function formatCode(
|
||||
Object.fromEntries(
|
||||
inputs.map((x) => {
|
||||
return [x?.input_id, ""];
|
||||
}),
|
||||
})
|
||||
),
|
||||
null,
|
||||
2,
|
||||
2
|
||||
)
|
||||
.split("\n")
|
||||
.map((line, index) => (index === 0 ? line : ` ${line}`)) // Add two spaces indentation except for the first line
|
||||
.join("\n")}`,
|
||||
.join("\n")}`
|
||||
);
|
||||
} else {
|
||||
codeTemplate = codeTemplate.replace(
|
||||
`
|
||||
inputs: {}`,
|
||||
"",
|
||||
""
|
||||
);
|
||||
}
|
||||
return codeTemplate
|
||||
|
||||
@@ -5,58 +5,33 @@ import { getRelativeTime } from "@/lib/getRelativeTime";
|
||||
import type { findAllDeployments } from "@/server/findAllRuns";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export function SharePageDeploymentRow({
|
||||
deployment,
|
||||
}: {
|
||||
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
||||
}) {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<TableRow
|
||||
className="appearance-none hover:cursor-pointer"
|
||||
onClick={() => {
|
||||
if (deployment.environment === "public-share") {
|
||||
router.push(
|
||||
`/share/${deployment.share_slug ?? deployment.id}/settings`,
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TableCell className="capitalize truncate">
|
||||
{deployment.environment}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{deployment.version?.version}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{deployment.machine?.name}
|
||||
</TableCell>
|
||||
<TableCell className="text-right truncate">
|
||||
{getRelativeTime(deployment.updated_at)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
export function DeploymentRow({
|
||||
deployment,
|
||||
deployment,
|
||||
}: {
|
||||
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
||||
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<TableCell className="capitalize truncate">
|
||||
{deployment.environment}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{deployment.version?.version}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{deployment.machine?.name}
|
||||
</TableCell>
|
||||
<TableCell className="text-right truncate">
|
||||
{getRelativeTime(deployment.updated_at)}
|
||||
</TableCell>
|
||||
</>
|
||||
);
|
||||
const router = useRouter();
|
||||
return (
|
||||
<TableRow
|
||||
className="appearance-none hover:cursor-pointer"
|
||||
onClick={() => {
|
||||
if (deployment.environment == "public-share") {
|
||||
router.push(`/share/${deployment.id}/settings`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TableCell className="capitalize truncate">
|
||||
{deployment.environment}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{deployment.version?.version}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{deployment.machine?.name}
|
||||
</TableCell>
|
||||
<TableCell className="text-right truncate">
|
||||
{getRelativeTime(deployment.updated_at)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ export const columns: ColumnDef<Machine>[] = [
|
||||
href={machine.endpoint.replace(
|
||||
"comfyui-api",
|
||||
"comfyui-app"
|
||||
)} rel="noreferrer"
|
||||
)}
|
||||
>
|
||||
Open ComfyUI
|
||||
</a>
|
||||
|
||||
@@ -29,7 +29,6 @@ export function Navbar() {
|
||||
const { organization } = useOrganization();
|
||||
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
||||
const [isDesktop, setIsDesktop] = useState(true);
|
||||
const [isSheetOpen, setSheetOpen] = useState(false);
|
||||
useEffect(() => {
|
||||
setIsDesktop(_isDesktop);
|
||||
}, [_isDesktop]);
|
||||
@@ -37,7 +36,7 @@ export function Navbar() {
|
||||
<>
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{!isDesktop && (
|
||||
<Sheet open={isSheetOpen} onOpenChange={(open) => setSheetOpen(open)}>
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<button className="flex items-center justify-center w-8 h-8 p-2">
|
||||
<Menu />
|
||||
@@ -48,10 +47,7 @@ export function Navbar() {
|
||||
<SheetTitle className="text-start">Comfy Deploy</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="grid h-full grid-rows-[1fr_auto]">
|
||||
<NavbarMenu
|
||||
className=" h-full"
|
||||
closeSheet={() => setSheetOpen(false)}
|
||||
/>
|
||||
<NavbarMenu className=" h-full" />
|
||||
{/* <OrganizationSwitcher
|
||||
appearance={{
|
||||
elements: {
|
||||
@@ -102,7 +98,7 @@ export function Navbar() {
|
||||
variant="outline"
|
||||
className="rounded-full aspect-square p-2"
|
||||
>
|
||||
<a target="_blank" href="https://github.com/BennyKok/comfyui-deploy" rel="noreferrer">
|
||||
<a target="_blank" href="https://github.com/BennyKok/comfyui-deploy">
|
||||
<Github />
|
||||
</a>
|
||||
</Button>
|
||||
|
||||
@@ -9,13 +9,7 @@ import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useMediaQuery } from "usehooks-ts";
|
||||
|
||||
export function NavbarMenu({
|
||||
className,
|
||||
closeSheet,
|
||||
}: {
|
||||
className?: string;
|
||||
closeSheet?: () => void;
|
||||
}) {
|
||||
export function NavbarMenu({ className }: { className?: string }) {
|
||||
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
||||
const [isDesktop, setIsDesktop] = useState(true);
|
||||
useEffect(() => {
|
||||
@@ -40,10 +34,6 @@ export function NavbarMenu({
|
||||
name: "API Keys",
|
||||
path: "/api-keys",
|
||||
},
|
||||
{
|
||||
name: "Examples",
|
||||
path: "/examples"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -52,9 +42,9 @@ export function NavbarMenu({
|
||||
{isDesktop && (
|
||||
<Tabs
|
||||
defaultValue={pathname}
|
||||
className="w-fit flex pointer-events-auto"
|
||||
className="w-[300px] flex pointer-events-auto"
|
||||
>
|
||||
<TabsList className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
{pages.map((page) => (
|
||||
<TabsTrigger
|
||||
key={page.name}
|
||||
@@ -78,9 +68,6 @@ export function NavbarMenu({
|
||||
<Link
|
||||
key={page.name}
|
||||
href={page.path}
|
||||
onClick={() => {
|
||||
if (!!closeSheet) closeSheet();
|
||||
}}
|
||||
className="p-2 hover:bg-gray-100/20 hover:underline"
|
||||
>
|
||||
{page.name}
|
||||
|
||||
@@ -5,20 +5,6 @@ export async function OutputRender(props: {
|
||||
run_id: string;
|
||||
filename: string;
|
||||
}) {
|
||||
if (props.filename.endsWith(".mp4") || props.filename.endsWith(".webm")) {
|
||||
const url = await getFileDownloadUrl(
|
||||
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||
);
|
||||
|
||||
return (
|
||||
<video controls autoPlay className="w-[400px]">
|
||||
<source src={url} type="video/mp4" />
|
||||
<source src={url} type="video/webm" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
props.filename.endsWith(".png") ||
|
||||
props.filename.endsWith(".gif") ||
|
||||
@@ -26,13 +12,13 @@ export async function OutputRender(props: {
|
||||
props.filename.endsWith(".jpeg")
|
||||
) {
|
||||
const url = await getFileDownloadUrl(
|
||||
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||
`outputs/runs/${props.run_id}/${props.filename}`
|
||||
);
|
||||
|
||||
return <img className="max-w-[200px]" alt={props.filename} src={url} />;
|
||||
} else {
|
||||
const url = await getFileDownloadUrl(
|
||||
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||
`outputs/runs/${props.run_id}/${props.filename}`
|
||||
);
|
||||
// console.log(url);
|
||||
|
||||
|
||||
@@ -1,74 +1,60 @@
|
||||
import { LiveStatus } from "./LiveStatus";
|
||||
import { RunInputs } from "@/components/RunInputs";
|
||||
import { RunOutputs } from "@/components/RunOutputs";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { TableCell, TableRow } from "@/components/ui/table";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { getDuration, getRelativeTime } from "@/lib/getRelativeTime";
|
||||
import { getRelativeTime } from "@/lib/getRelativeTime";
|
||||
import { type findAllRuns } from "@/server/findAllRuns";
|
||||
import { Suspense } from "react";
|
||||
import { LiveStatus } from "./LiveStatus";
|
||||
|
||||
export async function RunDisplay({
|
||||
run,
|
||||
run,
|
||||
}: {
|
||||
run: Awaited<ReturnType<typeof findAllRuns>>[0];
|
||||
run: Awaited<ReturnType<typeof findAllRuns>>[0];
|
||||
}) {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
||||
<TableRow>
|
||||
<TableCell>{run.number}</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{run.machine?.name}
|
||||
</TableCell>
|
||||
<TableCell className="truncate">
|
||||
{getRelativeTime(run.created_at)}
|
||||
</TableCell>
|
||||
<TableCell>{run.version?.version}</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline" className="truncate">
|
||||
{run.origin}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="truncate">
|
||||
<Tooltip>
|
||||
<TooltipTrigger>{getDuration(run.duration)}</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div>Cold start: {getDuration(run.cold_start_duration)}</div>
|
||||
<div>Run duration: {getDuration(run.run_duration)}</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<LiveStatus run={run} />
|
||||
</TableRow>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Run outputs</DialogTitle>
|
||||
<DialogDescription>
|
||||
You can view your run's outputs here
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="max-h-96 overflow-y-scroll">
|
||||
<RunInputs run={run} />
|
||||
<Suspense>
|
||||
<RunOutputs run_id={run.id} />
|
||||
</Suspense>
|
||||
</div>
|
||||
{/* <div className="max-h-96 overflow-y-scroll">{view}</div> */}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
||||
<TableRow>
|
||||
<TableCell>{run.number}</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{run.machine?.name}
|
||||
</TableCell>
|
||||
<TableCell className="truncate">
|
||||
{getRelativeTime(run.created_at)}
|
||||
</TableCell>
|
||||
<TableCell>{run.version?.version}</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline" className="truncate">
|
||||
{run.origin}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<LiveStatus run={run} />
|
||||
</TableRow>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Run outputs</DialogTitle>
|
||||
<DialogDescription>
|
||||
You can view your run's outputs here
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="max-h-96 overflow-y-scroll">
|
||||
<RunInputs run={run} />
|
||||
<Suspense>
|
||||
<RunOutputs run_id={run.id} />
|
||||
</Suspense>
|
||||
</div>
|
||||
{/* <div className="max-h-96 overflow-y-scroll">{view}</div> */}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import {
|
||||
findAllDeployments,
|
||||
findAllRunsWithCounts,
|
||||
} from "../server/findAllRuns";
|
||||
import { DeploymentDisplay } from "./DeploymentDisplay";
|
||||
import { PaginationControl } from "./PaginationControl";
|
||||
import { RunDisplay } from "./RunDisplay";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -8,13 +15,6 @@ import {
|
||||
} from "@/components/ui/table";
|
||||
import { parseAsInteger } from "next-usequerystate";
|
||||
import { headers } from "next/headers";
|
||||
import {
|
||||
findAllDeployments,
|
||||
findAllRunsWithCounts,
|
||||
} from "../server/findAllRuns";
|
||||
import { DeploymentDisplay } from "./DeploymentDisplay";
|
||||
import { PaginationControl } from "./PaginationControl";
|
||||
import { RunDisplay } from "./RunDisplay";
|
||||
|
||||
const itemPerPage = 6;
|
||||
const pageParser = parseAsInteger.withDefault(1);
|
||||
@@ -33,40 +33,39 @@ export async function RunsTable(props: {
|
||||
offset: (page - 1) * itemPerPage,
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<div className="overflow-auto h-fit w-full">
|
||||
<Table className="">
|
||||
{allRuns.length === 0 && (
|
||||
<TableCaption>A list of your recent runs.</TableCaption>
|
||||
)}
|
||||
<TableHeader className="bg-background top-0 sticky">
|
||||
<TableRow>
|
||||
<TableHead className="truncate">Number</TableHead>
|
||||
<TableHead className="truncate">Machine</TableHead>
|
||||
<TableHead className="truncate">Time</TableHead>
|
||||
<TableHead className="truncate">Version</TableHead>
|
||||
<TableHead className="truncate">Origin</TableHead>
|
||||
<TableHead className="truncate">Duration</TableHead>
|
||||
<TableHead className="truncate">Live Status</TableHead>
|
||||
<TableHead className="text-right">Status</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{allRuns.map((run) => (
|
||||
<RunDisplay run={run} key={run.id} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div>
|
||||
<div className="overflow-auto h-fit w-full">
|
||||
<Table className="">
|
||||
{allRuns.length == 0 && (
|
||||
<TableCaption>A list of your recent runs.</TableCaption>
|
||||
)}
|
||||
<TableHeader className="bg-background top-0 sticky">
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">Number</TableHead>
|
||||
<TableHead className="">Machine</TableHead>
|
||||
<TableHead className="">Time</TableHead>
|
||||
<TableHead className="w-[100px]">Version</TableHead>
|
||||
<TableHead className="truncate">Origin</TableHead>
|
||||
<TableHead className="truncate">Live Status</TableHead>
|
||||
<TableHead className="text-right">Status</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{allRuns.map((run) => (
|
||||
<RunDisplay run={run} key={run.id} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
|
||||
{Math.ceil(total / itemPerPage) > 0 && (
|
||||
<PaginationControl
|
||||
totalPage={Math.ceil(total / itemPerPage)}
|
||||
currentPage={page}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
{Math.ceil(total / itemPerPage) > 0 && (
|
||||
<PaginationControl
|
||||
totalPage={Math.ceil(total / itemPerPage)}
|
||||
currentPage={page}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export async function DeploymentsTable(props: { workflow_id: string }) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useServerActionData } from "./useServerActionData";
|
||||
import { ButtonAction } from "@/components/ButtonActionLoader";
|
||||
import { UpdateModal } from "@/components/InsertModal";
|
||||
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
|
||||
@@ -14,7 +15,6 @@ import { ExternalLink } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useServerActionData } from "./useServerActionData";
|
||||
|
||||
export function SharePageSettings({
|
||||
deployment_id,
|
||||
@@ -58,14 +58,13 @@ export function SharePageSettings({
|
||||
type="button"
|
||||
>
|
||||
<ButtonAction
|
||||
routerAction="back"
|
||||
action={removePublicShareDeployment.bind(null, deployment.id)}
|
||||
>
|
||||
Remove
|
||||
</ButtonAction>
|
||||
</Button>
|
||||
<Button asChild className="gap-2 truncate" type="button">
|
||||
<Link href={`/share/${deployment.share_slug ?? deployment.id}`} target="_blank">
|
||||
<Link href={`/share/${deployment.id}`} target="_blank">
|
||||
View Share Page <ExternalLink size={14} />
|
||||
</Link>
|
||||
</Button>
|
||||
@@ -80,11 +79,6 @@ export function SharePageSettings({
|
||||
description="Edit share page details."
|
||||
serverAction={updateSharePageInfo}
|
||||
formSchema={publicShareDeployment}
|
||||
fieldConfig={{
|
||||
description: {
|
||||
fieldType: "textarea",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { workflowVersionInputsToZod } from "../lib/workflowVersionInputsToZod";
|
||||
import { callServerPromise } from "./callServerPromise";
|
||||
import fetcher from "./fetcher";
|
||||
import { LoadingIcon } from "@/components/LoadingIcon";
|
||||
import AutoForm, { AutoFormSubmit } from "@/components/ui/auto-form";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -43,11 +46,11 @@ import type { getMachines } from "@/server/curdMachine";
|
||||
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
|
||||
import {
|
||||
Copy,
|
||||
Edit,
|
||||
ExternalLink,
|
||||
Info,
|
||||
MoreVertical,
|
||||
Play,
|
||||
Share,
|
||||
} from "lucide-react";
|
||||
import { parseAsInteger, useQueryState } from "next-usequerystate";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
@@ -55,11 +58,6 @@ import { toast } from "sonner";
|
||||
import useSWR from "swr";
|
||||
import type { z } from "zod";
|
||||
import { create } from "zustand";
|
||||
import { workflowVersionInputsToZod } from "../lib/workflowVersionInputsToZod";
|
||||
import { callServerPromise } from "./callServerPromise";
|
||||
import fetcher from "./fetcher";
|
||||
import { ButtonAction } from "@/components/ButtonActionLoader";
|
||||
import { editWorkflowOnMachine } from "@/server/editWorkflowOnMachine";
|
||||
|
||||
export function VersionSelect({
|
||||
workflow,
|
||||
@@ -124,48 +122,12 @@ export function MachineSelect({
|
||||
);
|
||||
}
|
||||
|
||||
type SelectedMachineStore = {
|
||||
selectedMachine: string | undefined;
|
||||
setSelectedMachine: (machine: string) => void;
|
||||
};
|
||||
function useSelectedMachine(machines: Awaited<ReturnType<typeof getMachines>>) {
|
||||
const a = useQueryState("machine", {
|
||||
defaultValue: machines?.[0]?.id ?? "",
|
||||
});
|
||||
|
||||
export const selectedMachineStore = create<SelectedMachineStore>((set) => ({
|
||||
selectedMachine: undefined,
|
||||
setSelectedMachine: (machine) => set(() => ({ selectedMachine: machine })),
|
||||
}));
|
||||
|
||||
export function useSelectedMachine(
|
||||
machines: Awaited<ReturnType<typeof getMachines>>,
|
||||
): [string, (v: string) => void] {
|
||||
const { selectedMachine, setSelectedMachine } = selectedMachineStore();
|
||||
return [selectedMachine ?? machines?.[0]?.id ?? "", setSelectedMachine];
|
||||
|
||||
// const searchParams = useSearchParams();
|
||||
// const pathname = usePathname();
|
||||
// const router = useRouter();
|
||||
|
||||
// const createQueryString = useCallback(
|
||||
// (name: string, value: string) => {
|
||||
// const params = new URLSearchParams(searchParams.toString());
|
||||
// params.set(name, value);
|
||||
|
||||
// return params.toString();
|
||||
// },
|
||||
// [searchParams],
|
||||
// );
|
||||
|
||||
// return [
|
||||
// searchParams.get("machine") ?? machines?.[0]?.id ?? "",
|
||||
// (v: string) => {
|
||||
// // window.history.pushState(
|
||||
// // "new url",
|
||||
// // "",
|
||||
// // pathname + "?" + createQueryString("machine", v),
|
||||
// // );
|
||||
// // router.push(pathname + "?" + createQueryString("machine", v));
|
||||
// router.replace(pathname + "?" + createQueryString("machine", v));
|
||||
// },
|
||||
// ];
|
||||
return a;
|
||||
}
|
||||
|
||||
type PublicRunStore = {
|
||||
@@ -262,7 +224,7 @@ export function RunWorkflowButton({
|
||||
const schema = useMemo(() => {
|
||||
const workflow_version = getWorkflowVersionFromVersionIndex(
|
||||
workflow,
|
||||
version,
|
||||
version
|
||||
);
|
||||
|
||||
if (!workflow_version) return null;
|
||||
@@ -276,7 +238,7 @@ export function RunWorkflowButton({
|
||||
const val = Object.keys(values).length > 0 ? values : undefined;
|
||||
|
||||
const workflow_version_id = workflow?.versions.find(
|
||||
(x) => x.version === version,
|
||||
(x) => x.version === version
|
||||
)?.id;
|
||||
console.log(workflow_version_id);
|
||||
if (!workflow_version_id) return;
|
||||
@@ -291,7 +253,7 @@ export function RunWorkflowButton({
|
||||
machine_id: machine,
|
||||
inputs: val,
|
||||
runOrigin: "manual",
|
||||
}),
|
||||
})
|
||||
);
|
||||
// console.log(res.json());
|
||||
setIsLoading(false);
|
||||
@@ -360,7 +322,7 @@ export function CreateDeploymentButton({
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const workflow_version_id = workflow?.versions.find(
|
||||
(x) => x.version === version,
|
||||
(x) => x.version === version
|
||||
)?.id;
|
||||
return (
|
||||
<DropdownMenu>
|
||||
@@ -380,8 +342,8 @@ export function CreateDeploymentButton({
|
||||
workflow.id,
|
||||
workflow_version_id,
|
||||
machine,
|
||||
"production",
|
||||
),
|
||||
"production"
|
||||
)
|
||||
);
|
||||
setIsLoading(false);
|
||||
}}
|
||||
@@ -398,8 +360,8 @@ export function CreateDeploymentButton({
|
||||
workflow.id,
|
||||
workflow_version_id,
|
||||
machine,
|
||||
"staging",
|
||||
),
|
||||
"staging"
|
||||
)
|
||||
);
|
||||
setIsLoading(false);
|
||||
}}
|
||||
@@ -411,7 +373,7 @@ export function CreateDeploymentButton({
|
||||
);
|
||||
}
|
||||
|
||||
export function OpenEditButton({
|
||||
export function CreateShareButton({
|
||||
workflow,
|
||||
machines,
|
||||
}: {
|
||||
@@ -423,34 +385,40 @@ export function OpenEditButton({
|
||||
...parseAsInteger,
|
||||
});
|
||||
const [machine] = useSelectedMachine(machines);
|
||||
const workflow_version_id = workflow?.versions.find(
|
||||
(x) => x.version == version,
|
||||
)?.id;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const workflow_version_id = workflow?.versions.find(
|
||||
(x) => x.version === version
|
||||
)?.id;
|
||||
|
||||
return (
|
||||
workflow_version_id &&
|
||||
machine && (
|
||||
<Button
|
||||
className="gap-2"
|
||||
onClick={async () => {
|
||||
setIsLoading(true);
|
||||
const url = await callServerPromise(
|
||||
editWorkflowOnMachine(workflow_version_id, machine),
|
||||
);
|
||||
if (url && typeof url !== "object") {
|
||||
window.open(url, "_blank");
|
||||
} else if (url && typeof url === "object" && url.error) {
|
||||
console.error(url.error);
|
||||
}
|
||||
setIsLoading(false);
|
||||
}}
|
||||
// asChild
|
||||
variant="outline"
|
||||
>
|
||||
Edit {isLoading ? <LoadingIcon /> : <Edit size={14} />}
|
||||
</Button>
|
||||
)
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button className="gap-2" disabled={isLoading} variant="outline">
|
||||
Share {isLoading ? <LoadingIcon /> : <Share size={14} />}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56">
|
||||
<DropdownMenuItem
|
||||
onClick={async () => {
|
||||
if (!workflow_version_id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await callServerPromise(
|
||||
createDeployments(
|
||||
workflow.id,
|
||||
workflow_version_id,
|
||||
machine,
|
||||
"public-share"
|
||||
)
|
||||
);
|
||||
setIsLoading(false);
|
||||
}}
|
||||
>
|
||||
Public
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -464,7 +432,7 @@ export function CopyWorkflowVersion({
|
||||
...parseAsInteger,
|
||||
});
|
||||
const workflow_version = workflow?.versions.find(
|
||||
(x) => x.version === version,
|
||||
(x) => x.version === version
|
||||
);
|
||||
return (
|
||||
<DropdownMenu>
|
||||
@@ -488,7 +456,7 @@ export function CopyWorkflowVersion({
|
||||
});
|
||||
|
||||
navigator.clipboard.writeText(
|
||||
JSON.stringify(workflow_version?.workflow),
|
||||
JSON.stringify(workflow_version?.workflow)
|
||||
);
|
||||
toast("Copied to clipboard");
|
||||
}}
|
||||
@@ -498,7 +466,7 @@ export function CopyWorkflowVersion({
|
||||
<DropdownMenuItem
|
||||
onClick={async () => {
|
||||
navigator.clipboard.writeText(
|
||||
JSON.stringify(workflow_version?.workflow_api),
|
||||
JSON.stringify(workflow_version?.workflow_api)
|
||||
);
|
||||
toast("Copied to clipboard");
|
||||
}}
|
||||
@@ -512,7 +480,7 @@ export function CopyWorkflowVersion({
|
||||
|
||||
export function getWorkflowVersionFromVersionIndex(
|
||||
workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>,
|
||||
version: number,
|
||||
version: number
|
||||
) {
|
||||
const workflow_version = workflow?.versions.find((x) => x.version == version);
|
||||
|
||||
@@ -538,7 +506,7 @@ export function ViewWorkflowDetailsButton({
|
||||
isLoading: isNodesIndexLoading,
|
||||
} = useSWR(
|
||||
"https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/extension-node-map.json",
|
||||
fetcher,
|
||||
fetcher
|
||||
);
|
||||
|
||||
const groupedByAuxName = useMemo(() => {
|
||||
@@ -548,7 +516,7 @@ export function ViewWorkflowDetailsButton({
|
||||
|
||||
const workflow_version = getWorkflowVersionFromVersionIndex(
|
||||
workflow,
|
||||
version,
|
||||
version
|
||||
);
|
||||
|
||||
const api = workflow_version?.workflow_api;
|
||||
@@ -559,7 +527,7 @@ export function ViewWorkflowDetailsButton({
|
||||
.map(([_, value]) => {
|
||||
const classType = value.class_type;
|
||||
const classTypeData = Object.entries(data).find(([_, nodeArray]) =>
|
||||
nodeArray[0].includes(classType),
|
||||
nodeArray[0].includes(classType)
|
||||
);
|
||||
return classTypeData ? { node: value, classTypeData } : null;
|
||||
})
|
||||
@@ -589,7 +557,7 @@ export function ViewWorkflowDetailsButton({
|
||||
node: z.infer<typeof workflowAPINodeType>[];
|
||||
url: string;
|
||||
}
|
||||
>,
|
||||
>
|
||||
);
|
||||
|
||||
// console.log(groupedByAuxName);
|
||||
@@ -631,7 +599,6 @@ export function ViewWorkflowDetailsButton({
|
||||
href={group.url}
|
||||
target="_blank"
|
||||
className="hover:underline"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{key}
|
||||
<ExternalLink
|
||||
|
||||
@@ -21,8 +21,8 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { getAllUserWorkflow } from "@/server/crudWorkflow";
|
||||
import { deleteWorkflow } from "@/server/deleteWorkflow";
|
||||
import type { getAllUserWorkflow } from "@/server/getAllUserWorkflow";
|
||||
import type {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
@@ -169,7 +169,7 @@ export const columns: ColumnDef<WorkflowItemList>[] = [
|
||||
export function WorkflowList({ data }: { data: WorkflowItemList[] }) {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[],
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
@@ -218,7 +218,7 @@ export function WorkflowList({ data }: { data: WorkflowItemList[] }) {
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext(),
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
@@ -237,7 +237,7 @@ export function WorkflowList({ data }: { data: WorkflowItemList[] }) {
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
cell.getContext()
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
@@ -5,5 +5,4 @@ export const customInputNodes: Record<string, string> = {
|
||||
ComfyUIDeployExternalNumber: "float",
|
||||
ComfyUIDeployExternalNumberInt: "integer",
|
||||
ComfyUIDeployExternalLora: "string - (public lora download url)",
|
||||
ComfyUIDeployExternalCheckpoint: "string - (public checkpoints download url)",
|
||||
};
|
||||
|
||||
@@ -69,7 +69,7 @@ const FeedbackThanks = forwardRef<React.ElementRef<'div'>>(
|
||||
)
|
||||
|
||||
export function Feedback() {
|
||||
const [submitted, setSubmitted] = useState(false)
|
||||
let [submitted, setSubmitted] = useState(false)
|
||||
|
||||
function onSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault()
|
||||
|
||||
@@ -8,7 +8,7 @@ export function Prose<T extends React.ElementType = 'div'>({
|
||||
as?: T
|
||||
className?: string
|
||||
}) {
|
||||
const Component = as ?? 'div'
|
||||
let Component = as ?? 'div'
|
||||
|
||||
return (
|
||||
<Component
|
||||
|
||||
@@ -22,9 +22,9 @@ function MoonIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
}
|
||||
|
||||
export function ThemeToggle() {
|
||||
const { resolvedTheme, setTheme } = useTheme()
|
||||
const otherTheme = resolvedTheme === 'dark' ? 'light' : 'dark'
|
||||
const [mounted, setMounted] = useState(false)
|
||||
let { resolvedTheme, setTheme } = useTheme()
|
||||
let otherTheme = resolvedTheme === 'dark' ? 'light' : 'dark'
|
||||
let [mounted, setMounted] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
|
||||
+4
-12
@@ -1,19 +1,11 @@
|
||||
import { Pool, neonConfig } from "@neondatabase/serverless";
|
||||
import { drizzle as neonDrizzle } from "drizzle-orm/neon-serverless";
|
||||
import * as schema from "./schema";
|
||||
|
||||
const isDevContainer = process.env.REMOTE_CONTAINERS !== undefined;
|
||||
import { neonConfig, Pool } from "@neondatabase/serverless";
|
||||
import { drizzle as neonDrizzle } from "drizzle-orm/neon-serverless";
|
||||
|
||||
// if we're running locally
|
||||
if (process.env.VERCEL_ENV !== "production") {
|
||||
// Set the WebSocket proxy to work with the local instance
|
||||
if (isDevContainer) {
|
||||
// Running inside a VS Code devcontainer
|
||||
neonConfig.wsProxy = (host) => "host.docker.internal:5481/v1";
|
||||
} else {
|
||||
// Not running inside a VS Code devcontainer
|
||||
neonConfig.wsProxy = (host) => `${host}:5481/v1`;
|
||||
}
|
||||
neonConfig.wsProxy = (host) => `${host}:5481/v1`;
|
||||
// Disable all authentication and encryption
|
||||
neonConfig.useSecureWebSocket = false;
|
||||
neonConfig.pipelineTLS = false;
|
||||
@@ -26,5 +18,5 @@ export const db = neonDrizzle(
|
||||
}),
|
||||
{
|
||||
schema,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
+14
-29
@@ -1,15 +1,15 @@
|
||||
import { type InferSelectModel, relations } from "drizzle-orm";
|
||||
import { relations, type InferSelectModel } from "drizzle-orm";
|
||||
import {
|
||||
boolean,
|
||||
text,
|
||||
pgSchema,
|
||||
uuid,
|
||||
integer,
|
||||
timestamp,
|
||||
jsonb,
|
||||
pgEnum,
|
||||
pgSchema,
|
||||
text,
|
||||
timestamp,
|
||||
uuid,
|
||||
boolean,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
export const dbSchema = pgSchema("comfyui_deploy");
|
||||
@@ -35,8 +35,6 @@ export const workflowTable = dbSchema.table("workflows", {
|
||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export const workflowSchema = createSelectSchema(workflowTable);
|
||||
|
||||
export const workflowRelations = relations(workflowTable, ({ many, one }) => ({
|
||||
user: one(usersTable, {
|
||||
fields: [workflowTable.user_id],
|
||||
@@ -81,7 +79,6 @@ export const workflowVersionTable = dbSchema.table("workflow_versions", {
|
||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
export const workflowVersionSchema = createSelectSchema(workflowVersionTable);
|
||||
|
||||
export const workflowVersionRelations = relations(
|
||||
workflowVersionTable,
|
||||
@@ -90,7 +87,7 @@ export const workflowVersionRelations = relations(
|
||||
fields: [workflowVersionTable.workflow_id],
|
||||
references: [workflowTable.id],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
export const workflowRunStatus = pgEnum("workflow_run_status", [
|
||||
@@ -139,7 +136,7 @@ export const workflowRunsTable = dbSchema.table("workflow_runs", {
|
||||
() => workflowVersionTable.id,
|
||||
{
|
||||
onDelete: "set null",
|
||||
},
|
||||
}
|
||||
),
|
||||
workflow_inputs:
|
||||
jsonb("workflow_inputs").$type<Record<string, string | number>>(),
|
||||
@@ -156,7 +153,6 @@ export const workflowRunsTable = dbSchema.table("workflow_runs", {
|
||||
status: workflowRunStatus("status").notNull().default("not-started"),
|
||||
ended_at: timestamp("ended_at"),
|
||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||
started_at: timestamp("started_at"),
|
||||
});
|
||||
|
||||
export const workflowRunRelations = relations(
|
||||
@@ -175,7 +171,7 @@ export const workflowRunRelations = relations(
|
||||
fields: [workflowRunsTable.workflow_id],
|
||||
references: [workflowTable.id],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
// We still want to keep the workflow run record.
|
||||
@@ -199,7 +195,7 @@ export const workflowOutputRelations = relations(
|
||||
fields: [workflowRunOutputs.run_id],
|
||||
references: [workflowRunsTable.id],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
// when user delete, also delete all the workflow versions
|
||||
@@ -232,7 +228,7 @@ export const snapshotType = z.object({
|
||||
z.object({
|
||||
hash: z.string(),
|
||||
disabled: z.boolean(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
file_custom_nodes: z.array(z.any()),
|
||||
});
|
||||
@@ -247,7 +243,7 @@ export const showcaseMedia = z.array(
|
||||
z.object({
|
||||
url: z.string(),
|
||||
isCover: z.boolean().default(false),
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
export const showcaseMediaNullable = z
|
||||
@@ -255,7 +251,7 @@ export const showcaseMediaNullable = z
|
||||
z.object({
|
||||
url: z.string(),
|
||||
isCover: z.boolean().default(false),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.nullable();
|
||||
|
||||
@@ -278,7 +274,6 @@ export const deploymentsTable = dbSchema.table("deployments", {
|
||||
machine_id: uuid("machine_id")
|
||||
.notNull()
|
||||
.references(() => machinesTable.id),
|
||||
share_slug: text("share_slug").unique(),
|
||||
description: text("description"),
|
||||
showcase_media:
|
||||
jsonb("showcase_media").$type<z.infer<typeof showcaseMedia>>(),
|
||||
@@ -334,16 +329,6 @@ export const apiKeyTable = dbSchema.table("api_keys", {
|
||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export const authRequestsTable = dbSchema.table("auth_requests", {
|
||||
request_id: text("request_id").primaryKey().notNull(),
|
||||
user_id: text("user_id"),
|
||||
org_id: text("org_id"),
|
||||
api_hash: text("api_hash"),
|
||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||
expired_date: timestamp("expired_date"),
|
||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export type UserType = InferSelectModel<typeof usersTable>;
|
||||
export type WorkflowType = InferSelectModel<typeof workflowTable>;
|
||||
export type MachineType = InferSelectModel<typeof machinesTable>;
|
||||
|
||||
@@ -1,26 +1,12 @@
|
||||
import dayjs from "dayjs";
|
||||
import duration from "dayjs/plugin/duration";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import React from "react";
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
dayjs.extend(duration);
|
||||
|
||||
export function getRelativeTime(time: string | Date | null | undefined) {
|
||||
if (typeof time === "string" || time instanceof Date) {
|
||||
return dayjs().to(time);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function formatDuration(seconds: number) {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
if (minutes > 0) {
|
||||
return `${minutes}.${remainingSeconds} mins`;
|
||||
} else {
|
||||
return `${remainingSeconds.toFixed(1)} secs`;
|
||||
}
|
||||
}
|
||||
|
||||
export function getDuration(durationInSecs: number) {
|
||||
return `${formatDuration(durationInSecs)}`;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
export function remToPx(remValue: number) {
|
||||
const rootFontSize =
|
||||
typeof window === "undefined"
|
||||
? 16
|
||||
: parseFloat(
|
||||
window.getComputedStyle(document.documentElement).fontSize,
|
||||
);
|
||||
let rootFontSize =
|
||||
typeof window === 'undefined'
|
||||
? 16
|
||||
: parseFloat(window.getComputedStyle(document.documentElement).fontSize)
|
||||
|
||||
return remValue * rootFontSize
|
||||
}
|
||||
|
||||
+10
-10
@@ -27,13 +27,13 @@ function rehypeShiki() {
|
||||
|
||||
visit(tree, "element", (node) => {
|
||||
if (node.tagName === "pre" && node.children[0]?.tagName === "code") {
|
||||
const codeNode = node.children[0];
|
||||
const textNode = codeNode.children[0];
|
||||
let codeNode = node.children[0];
|
||||
let textNode = codeNode.children[0];
|
||||
|
||||
node.properties.code = textNode.value;
|
||||
|
||||
if (node.properties.language) {
|
||||
const tokens = highlighter.codeToThemedTokens(
|
||||
let tokens = highlighter.codeToThemedTokens(
|
||||
textNode.value,
|
||||
node.properties.language
|
||||
);
|
||||
@@ -53,7 +53,7 @@ function rehypeShiki() {
|
||||
|
||||
function rehypeSlugify() {
|
||||
return (tree) => {
|
||||
const slugify = slugifyWithCounter();
|
||||
let slugify = slugifyWithCounter();
|
||||
visit(tree, "element", (node) => {
|
||||
if (node.tagName === "h2" && !node.properties.id) {
|
||||
node.properties.id = slugify(toString(node));
|
||||
@@ -64,10 +64,10 @@ function rehypeSlugify() {
|
||||
|
||||
function rehypeAddMDXExports(getExports) {
|
||||
return (tree) => {
|
||||
const exports = Object.entries(getExports(tree));
|
||||
let exports = Object.entries(getExports(tree));
|
||||
|
||||
for (const [name, value] of exports) {
|
||||
for (const node of tree.children) {
|
||||
for (let [name, value] of exports) {
|
||||
for (let node of tree.children) {
|
||||
if (
|
||||
node.type === "mdxjsEsm" &&
|
||||
new RegExp(`export\\s+const\\s+${name}\\s*=`).test(node.value)
|
||||
@@ -76,7 +76,7 @@ function rehypeAddMDXExports(getExports) {
|
||||
}
|
||||
}
|
||||
|
||||
const exportStr = `export const ${name} = ${value}`;
|
||||
let exportStr = `export const ${name} = ${value}`;
|
||||
|
||||
tree.children.push({
|
||||
type: "mdxjsEsm",
|
||||
@@ -93,9 +93,9 @@ function rehypeAddMDXExports(getExports) {
|
||||
}
|
||||
|
||||
function getSections(node) {
|
||||
const sections = [];
|
||||
let sections = [];
|
||||
|
||||
for (const child of node.children ?? []) {
|
||||
for (let child of node.children ?? []) {
|
||||
if (child.type === "element" && child.tagName === "h2") {
|
||||
sections.push(`{
|
||||
title: ${JSON.stringify(toString(child))},
|
||||
|
||||
@@ -31,9 +31,9 @@ function extractSections() {
|
||||
|
||||
visit(tree, (node) => {
|
||||
if (node.type === "heading" || node.type === "paragraph") {
|
||||
const content = toString(excludeObjectExpressions(node));
|
||||
let content = toString(excludeObjectExpressions(node));
|
||||
if (node.type === "heading" && node.depth <= 2) {
|
||||
const hash = node.depth === 1 ? null : slugify(content);
|
||||
let hash = node.depth === 1 ? null : slugify(content);
|
||||
sections.push([content, hash, []]);
|
||||
} else {
|
||||
sections.at(-1)?.[2].push(content);
|
||||
@@ -45,7 +45,7 @@ function extractSections() {
|
||||
}
|
||||
|
||||
export default function (nextConfig = {}) {
|
||||
const cache = new Map();
|
||||
let cache = new Map();
|
||||
|
||||
return Object.assign({}, nextConfig, {
|
||||
webpack(config, options) {
|
||||
@@ -53,20 +53,20 @@ export default function (nextConfig = {}) {
|
||||
test: __filename,
|
||||
use: [
|
||||
createLoader(function () {
|
||||
const appDir = path.resolve("./src/app/(docs)/docs");
|
||||
let appDir = path.resolve("./src/app/(docs)/docs");
|
||||
this.addContextDependency(appDir);
|
||||
|
||||
const files = glob.sync("**/*.mdx", { cwd: appDir });
|
||||
const data = files.map((file) => {
|
||||
let files = glob.sync("**/*.mdx", { cwd: appDir });
|
||||
let data = files.map((file) => {
|
||||
let url = `/${file.replace(/(^|\/)page\.mdx$/, "")}`;
|
||||
const mdx = fs.readFileSync(path.join(appDir, file), "utf8");
|
||||
let mdx = fs.readFileSync(path.join(appDir, file), "utf8");
|
||||
|
||||
let sections = [];
|
||||
|
||||
if (cache.get(file)?.[0] === mdx) {
|
||||
sections = cache.get(file)[1];
|
||||
} else {
|
||||
const vfile = { value: mdx, sections };
|
||||
let vfile = { value: mdx, sections };
|
||||
processor.runSync(processor.parse(vfile), vfile);
|
||||
cache.set(file, [mdx, sections]);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import type { ResponseConfig } from "@asteasolutions/zod-to-openapi";
|
||||
|
||||
|
||||
import { z } from "@hono/zod-openapi";
|
||||
|
||||
export const authError = {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { customAlphabet } from "nanoid";
|
||||
|
||||
export const nanoid = customAlphabet(
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
|
||||
);
|
||||
const prefixes = {
|
||||
img: "img",
|
||||
vid: "vid",
|
||||
} as const;
|
||||
|
||||
export function newId(prefix: keyof typeof prefixes): string {
|
||||
return [prefixes[prefix], nanoid(16)].join("_");
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { createRun } from "../server/createRun";
|
||||
import { db } from "@/db/db";
|
||||
import { deploymentsTable } from "@/db/schema";
|
||||
import type { App } from "@/routes/app";
|
||||
import { authError } from "@/routes/authError";
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { z, createRoute } from "@hono/zod-openapi";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { createRun } from "../server/createRun";
|
||||
|
||||
const createRunRoute = createRoute({
|
||||
method: "post",
|
||||
@@ -99,7 +99,7 @@ export const registerCreateRunRoute = (app: App) => {
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
import { db } from "@/db/db";
|
||||
import { authRequestsTable } from "@/db/schema";
|
||||
import type { App } from "@/routes/app";
|
||||
import { authError } from "@/routes/authError";
|
||||
import { z, createRoute } from "@hono/zod-openapi";
|
||||
import { eq } from "drizzle-orm";
|
||||
import jwt from "jsonwebtoken";
|
||||
import crypto from "crypto";
|
||||
import { getOrgOrUserDisplayName } from "@/server/getOrgOrUserDisplayName";
|
||||
import ms from "ms";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
path: "/auth-response/:request_id",
|
||||
tags: ["comfyui"],
|
||||
summary: "Get an API Key with code",
|
||||
description:
|
||||
"This endpoints is specifically built for ComfyUI workflow upload.",
|
||||
request: {
|
||||
params: z.object({
|
||||
request_id: z.string(),
|
||||
}),
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
api_key: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "The returned API Key",
|
||||
},
|
||||
201: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
message: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "The API key is not yet ready",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
error: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Error when fetching the API Key with code",
|
||||
},
|
||||
...authError,
|
||||
},
|
||||
});
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
||||
};
|
||||
|
||||
export const registerGetAuthResponse = (app: App) => {
|
||||
return app.openapi(route, async (c) => {
|
||||
const { request_id } = c.req.valid("param");
|
||||
|
||||
try {
|
||||
const result = await db.query.authRequestsTable.findFirst({
|
||||
where: eq(authRequestsTable.request_id, request_id),
|
||||
});
|
||||
|
||||
if (result?.api_hash) {
|
||||
return c.json(
|
||||
{
|
||||
message: "Already used.",
|
||||
},
|
||||
{
|
||||
status: 201,
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (result && result.user_id) {
|
||||
const expireTime = "1w";
|
||||
const token = jwt.sign(
|
||||
{ user_id: result.user_id, org_id: result.org_id },
|
||||
process.env.JWT_SECRET!,
|
||||
{
|
||||
expiresIn: expireTime,
|
||||
},
|
||||
);
|
||||
|
||||
const hash = crypto.createHash("sha256").update(token).digest("hex");
|
||||
|
||||
const now = new Date();
|
||||
const expiryDate = new Date(now.getTime() + ms(expireTime));
|
||||
|
||||
await db
|
||||
.update(authRequestsTable)
|
||||
.set({
|
||||
api_hash: hash,
|
||||
expired_date: expiryDate,
|
||||
})
|
||||
.where(eq(authRequestsTable.request_id, request_id));
|
||||
|
||||
const userName = await getOrgOrUserDisplayName(
|
||||
result.org_id,
|
||||
result.user_id,
|
||||
);
|
||||
|
||||
return c.json(
|
||||
{
|
||||
api_key: token,
|
||||
name: userName,
|
||||
},
|
||||
{
|
||||
status: 200,
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "Unknown error";
|
||||
return c.json(
|
||||
{
|
||||
error: errorMessage,
|
||||
},
|
||||
{
|
||||
statusText: "Invalid request",
|
||||
status: 500,
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
}
|
||||
return c.json(
|
||||
{
|
||||
message: "Not ready yet.",
|
||||
},
|
||||
{
|
||||
status: 201,
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
@@ -1,100 +0,0 @@
|
||||
import { workflowVersionSchema, workflowVersionTable } from "@/db/schema";
|
||||
import type { App } from "@/routes/app";
|
||||
import { authError } from "@/routes/authError";
|
||||
import { getWorkflowVersion } from "@/server/crudWorkflow";
|
||||
import { z, createRoute } from "@hono/zod-openapi";
|
||||
import { createSelectSchema } from "drizzle-zod";
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
path: "/workflow-version/:version_id",
|
||||
tags: ["comfyui"],
|
||||
summary: "Get comfyui workflow",
|
||||
description: "Use this to retrieve comfyui workflow by id",
|
||||
request: {
|
||||
params: z.object({
|
||||
version_id: z.string(),
|
||||
}),
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: createSelectSchema(workflowVersionTable, {
|
||||
workflow_api: (schema) =>
|
||||
schema.workflow_api.openapi({
|
||||
type: "object",
|
||||
}),
|
||||
workflow: (schema) =>
|
||||
schema.workflow.openapi({
|
||||
type: "object",
|
||||
}),
|
||||
snapshot: (schema) =>
|
||||
schema.snapshot.openapi({
|
||||
type: "object",
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Retrieve the output",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
error: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Error when uploading the workflow",
|
||||
},
|
||||
...authError,
|
||||
},
|
||||
});
|
||||
|
||||
export const registerGetWorkflowRoute = (app: App) => {
|
||||
return app.openapi(route, async (c) => {
|
||||
const { version_id } = c.req.valid("param");
|
||||
const apiUser = c.get("apiKeyTokenData")!;
|
||||
|
||||
if (!apiUser.user_id)
|
||||
return c.json(
|
||||
{
|
||||
error: "Invalid user_id",
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
const workflow_version = await getWorkflowVersion(apiUser, version_id);
|
||||
if (workflow_version) {
|
||||
return c.json(workflow_version, {
|
||||
status: 200,
|
||||
});
|
||||
} else {
|
||||
return c.json(
|
||||
{
|
||||
error: "No version found",
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "Unknown error";
|
||||
return c.json(
|
||||
{
|
||||
error: errorMessage,
|
||||
},
|
||||
{
|
||||
statusText: "Invalid request",
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -3,7 +3,20 @@ import { authError } from "@/routes/authError";
|
||||
import { getFileDownloadUrl } from "@/server/getFileDownloadUrl";
|
||||
import { handleResourceUpload } from "@/server/resource";
|
||||
import { z, createRoute } from "@hono/zod-openapi";
|
||||
import { newId } from "./newId";
|
||||
import { customAlphabet } from "nanoid";
|
||||
|
||||
export const nanoid = customAlphabet(
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
);
|
||||
|
||||
const prefixes = {
|
||||
img: "img",
|
||||
vid: "vid",
|
||||
} as const;
|
||||
|
||||
export function newId(prefix: keyof typeof prefixes): string {
|
||||
return [prefixes[prefix], nanoid(16)].join("_");
|
||||
}
|
||||
|
||||
const uploadUrlRoute = createRoute({
|
||||
method: "get",
|
||||
@@ -83,7 +96,7 @@ export const registerUploadRoute = (app: App) => {
|
||||
file_id: id,
|
||||
download_url: await getFileDownloadUrl(filePath),
|
||||
},
|
||||
200,
|
||||
200
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
@@ -94,7 +107,7 @@ export const registerUploadRoute = (app: App) => {
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
import { db } from "@/db/db";
|
||||
import {
|
||||
snapshotType,
|
||||
workflowAPIType,
|
||||
workflowTable,
|
||||
workflowType,
|
||||
} from "@/db/schema";
|
||||
import type { App } from "@/routes/app";
|
||||
import { authError } from "@/routes/authError";
|
||||
import {
|
||||
createNewWorkflow,
|
||||
createNewWorkflowVersion,
|
||||
} from "@/server/createNewWorkflow";
|
||||
import { z, createRoute } from "@hono/zod-openapi";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
|
||||
const route = createRoute({
|
||||
method: "post",
|
||||
path: "/workflow",
|
||||
tags: ["comfyui"],
|
||||
summary: "Upload workflow from ComfyUI",
|
||||
description:
|
||||
"This endpoints is specifically built for ComfyUI workflow upload.",
|
||||
request: {
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
workflow_id: z.string().optional(),
|
||||
workflow_name: z.string().min(1).optional(),
|
||||
workflow: workflowType,
|
||||
workflow_api: workflowAPIType,
|
||||
snapshot: snapshotType,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
workflow_id: z.string(),
|
||||
version: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Retrieve the output",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
error: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Error when uploading the workflow",
|
||||
},
|
||||
...authError,
|
||||
},
|
||||
});
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
||||
};
|
||||
|
||||
export const registerWorkflowUploadRoute = (app: App) => {
|
||||
app.openapi(route, async (c) => {
|
||||
const {
|
||||
// user_id,
|
||||
workflow,
|
||||
workflow_api,
|
||||
workflow_id: _workflow_id,
|
||||
workflow_name,
|
||||
snapshot,
|
||||
} = c.req.valid("json");
|
||||
const { org_id, user_id } = c.get("apiKeyTokenData")!;
|
||||
|
||||
if (!user_id)
|
||||
return c.json(
|
||||
{
|
||||
error: "Invalid user_id",
|
||||
},
|
||||
{
|
||||
headers: corsHeaders,
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
|
||||
let workflow_id = _workflow_id;
|
||||
|
||||
let version = -1;
|
||||
|
||||
try {
|
||||
if ((!workflow_id || workflow_id.length === 0) && workflow_name) {
|
||||
// Create a new parent workflow
|
||||
const { workflow_id: _workflow_id, version: _version } =
|
||||
await createNewWorkflow({
|
||||
user_id: user_id,
|
||||
org_id: org_id,
|
||||
workflow_name: workflow_name,
|
||||
workflowData: {
|
||||
workflow,
|
||||
workflow_api,
|
||||
snapshot,
|
||||
},
|
||||
});
|
||||
|
||||
workflow_id = _workflow_id;
|
||||
version = _version;
|
||||
} else if (workflow_id) {
|
||||
const _workflow = await db
|
||||
.select()
|
||||
.from(workflowTable)
|
||||
.where(
|
||||
and(
|
||||
eq(workflowTable.id, workflow_id),
|
||||
eq(workflowTable.user_id, user_id),
|
||||
org_id
|
||||
? eq(workflowTable.org_id, org_id)
|
||||
: isNull(workflowTable.org_id),
|
||||
),
|
||||
);
|
||||
|
||||
if (_workflow.length === 0) {
|
||||
return c.json(
|
||||
{
|
||||
error: "Invalid workflow_id",
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
statusText: "Invalid workflow_id",
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Case 2 update workflow
|
||||
const { version: _version } = await createNewWorkflowVersion({
|
||||
workflow_id: workflow_id,
|
||||
workflowData: {
|
||||
workflow,
|
||||
workflow_api,
|
||||
snapshot,
|
||||
},
|
||||
});
|
||||
version = _version;
|
||||
} else {
|
||||
return c.json(
|
||||
{
|
||||
error: "Invalid request, missing either workflow_id or name",
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
statusText: "Invalid request",
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "Unknown error";
|
||||
return c.json(
|
||||
{
|
||||
error: errorMessage,
|
||||
},
|
||||
{
|
||||
statusText: "Invalid request",
|
||||
status: 500,
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return c.json(
|
||||
{
|
||||
workflow_id: workflow_id,
|
||||
version: version,
|
||||
},
|
||||
{
|
||||
status: 200,
|
||||
headers: corsHeaders,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
app.route("/upload-workflow").options(async (c) => {
|
||||
return new Response(null, {
|
||||
status: 204,
|
||||
headers: corsHeaders,
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const APIKeyBodyRequest = z.object({
|
||||
user_id: z.string().optional().nullable(),
|
||||
org_id: z.string().optional().nullable(),
|
||||
user_id: z.string().optional(),
|
||||
org_id: z.string().optional(),
|
||||
iat: z.number(),
|
||||
exp: z.number().optional(),
|
||||
});
|
||||
|
||||
export type APIKeyUserType = z.infer<typeof APIKeyBodyRequest>;
|
||||
|
||||
@@ -17,7 +17,7 @@ export const insertCustomMachineSchema = createInsertSchema(machinesTable, {
|
||||
comfyui: "d0165d819afe76bd4e6bdd710eb5f3e571b6a804",
|
||||
git_custom_nodes: {
|
||||
"https://github.com/BennyKok/comfyui-deploy.git": {
|
||||
hash: "43fe0a384aa5fa9e141d4a264b2ed40a73b817bc",
|
||||
hash: "1e99474780951043e1b001e1877de3f2eb45cfba",
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,46 +1,6 @@
|
||||
import { db } from "@/db/db";
|
||||
import type { WorkflowVersionType } from "@/db/schema";
|
||||
import { workflowTable, workflowVersionTable } from "@/db/schema";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
|
||||
export async function createNewWorkflowVersion({
|
||||
workflow_id,
|
||||
workflowData,
|
||||
}: {
|
||||
workflow_id: string;
|
||||
workflowData: Pick<
|
||||
WorkflowVersionType,
|
||||
"workflow" | "workflow_api" | "snapshot"
|
||||
>;
|
||||
}) {
|
||||
// Add a new version
|
||||
const data = await db
|
||||
.insert(workflowVersionTable)
|
||||
.values({
|
||||
workflow_id,
|
||||
...workflowData,
|
||||
version: sql`(
|
||||
SELECT COALESCE(MAX(version), 0) + 1
|
||||
FROM ${workflowVersionTable}
|
||||
WHERE workflow_id = ${workflow_id}
|
||||
)`,
|
||||
})
|
||||
.returning();
|
||||
const version = data[0].version;
|
||||
|
||||
// Touch up the last updated time
|
||||
await db
|
||||
.update(workflowTable)
|
||||
.set({
|
||||
updated_at: new Date(),
|
||||
})
|
||||
.where(eq(workflowTable.id, workflow_id))
|
||||
.returning();
|
||||
|
||||
return {
|
||||
version,
|
||||
};
|
||||
}
|
||||
|
||||
export async function createNewWorkflow({
|
||||
workflow_name,
|
||||
@@ -50,7 +10,7 @@ export async function createNewWorkflow({
|
||||
}: {
|
||||
workflow_name: string;
|
||||
user_id: string;
|
||||
org_id?: string | null;
|
||||
org_id?: string;
|
||||
workflowData: Pick<
|
||||
WorkflowVersionType,
|
||||
"workflow" | "workflow_api" | "snapshot"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use server";
|
||||
|
||||
import { withServerPromise } from "./withServerPromise";
|
||||
import { db } from "@/db/db";
|
||||
import type {
|
||||
MachineType,
|
||||
@@ -15,7 +16,6 @@ import { and, eq } from "drizzle-orm";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import "server-only";
|
||||
import { v4 } from "uuid";
|
||||
import { withServerPromise } from "./withServerPromise";
|
||||
|
||||
export const createRun = withServerPromise(
|
||||
async ({
|
||||
@@ -38,7 +38,7 @@ export const createRun = withServerPromise(
|
||||
? await db.query.machinesTable.findFirst({
|
||||
where: and(
|
||||
eq(machinesTable.id, machine_id),
|
||||
eq(machinesTable.disabled, false),
|
||||
eq(machinesTable.disabled, false)
|
||||
),
|
||||
})
|
||||
: machine_id;
|
||||
@@ -91,11 +91,6 @@ export const createRun = withServerPromise(
|
||||
if (node.inputs["input_id"] === key) {
|
||||
node.inputs["input_id"] = inputs[key];
|
||||
}
|
||||
|
||||
// Fix for external text default value
|
||||
if (node.class_type == "ComfyUIDeployExternalText") {
|
||||
node.inputs["default_value"] = inputs[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -148,7 +143,7 @@ export const createRun = withServerPromise(
|
||||
throw new Error(
|
||||
`Error creating run, ${
|
||||
___result.statusText
|
||||
} ${await ___result.text()}`,
|
||||
} ${await ___result.text()}`
|
||||
);
|
||||
console.log(_data, ___result);
|
||||
break;
|
||||
@@ -182,7 +177,7 @@ export const createRun = withServerPromise(
|
||||
throw new Error(
|
||||
`Error creating run, ${
|
||||
__result.statusText
|
||||
} ${await __result.text()}`,
|
||||
} ${await __result.text()}`
|
||||
);
|
||||
console.log(data, __result);
|
||||
break;
|
||||
@@ -204,7 +199,7 @@ export const createRun = withServerPromise(
|
||||
let message = `Error creating run, ${_result.statusText}`;
|
||||
try {
|
||||
const result = await ComfyAPI_Run.parseAsync(
|
||||
await _result.json(),
|
||||
await _result.json()
|
||||
);
|
||||
message += ` ${result.node_errors}`;
|
||||
} catch (error) {}
|
||||
@@ -224,20 +219,11 @@ export const createRun = withServerPromise(
|
||||
throw e;
|
||||
}
|
||||
|
||||
// It successfully started, update the started_at time
|
||||
|
||||
await db
|
||||
.update(workflowRunsTable)
|
||||
.set({
|
||||
started_at: new Date(),
|
||||
})
|
||||
.where(eq(workflowRunsTable.id, workflow_run[0].id));
|
||||
|
||||
return {
|
||||
workflow_run_id: workflow_run[0].id,
|
||||
message: "Successful workflow run",
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export async function checkStatus(run_id: string) {
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
"use server";
|
||||
|
||||
import { db } from "@/db/db";
|
||||
import { apiKeyTable, authRequestsTable } from "@/db/schema";
|
||||
import { withServerPromise } from "@/server/withServerPromise";
|
||||
import { apiKeyTable } from "@/db/schema";
|
||||
import { auth } from "@clerk/nextjs";
|
||||
import { and, desc, eq, isNull } from "drizzle-orm";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
export const createAuthRequest = withServerPromise(
|
||||
async (request_id: string) => {
|
||||
const { userId, orgId } = auth();
|
||||
// export const nanoid = customAlphabet(
|
||||
// "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
// );
|
||||
|
||||
const result = await db.insert(authRequestsTable).values({
|
||||
request_id: request_id,
|
||||
user_id: userId,
|
||||
org_id: orgId,
|
||||
});
|
||||
// const prefixes = {
|
||||
// cd: "cd",
|
||||
// } as const;
|
||||
|
||||
return {
|
||||
message: "Auth request created, you may now return to your application.",
|
||||
};
|
||||
},
|
||||
);
|
||||
// function newId(prefix: keyof typeof prefixes): string {
|
||||
// return [prefixes[prefix], nanoid(16)].join("_");
|
||||
// }
|
||||
|
||||
export async function addNewAPIKey(name: string) {
|
||||
const { userId, orgId } = auth();
|
||||
@@ -34,7 +29,7 @@ export async function addNewAPIKey(name: string) {
|
||||
if (orgId) {
|
||||
token = jwt.sign(
|
||||
{ user_id: userId, org_id: orgId },
|
||||
process.env.JWT_SECRET!,
|
||||
process.env.JWT_SECRET!
|
||||
);
|
||||
} else {
|
||||
token = jwt.sign({ user_id: userId }, process.env.JWT_SECRET!);
|
||||
@@ -98,7 +93,7 @@ export async function getAPIKeys() {
|
||||
where: and(
|
||||
eq(apiKeyTable.user_id, userId),
|
||||
isNull(apiKeyTable.org_id),
|
||||
eq(apiKeyTable.revoked, false),
|
||||
eq(apiKeyTable.revoked, false)
|
||||
),
|
||||
orderBy: desc(apiKeyTable.created_at),
|
||||
});
|
||||
|
||||
@@ -7,19 +7,17 @@ import { createNewWorkflow } from "@/server/createNewWorkflow";
|
||||
import { addCustomMachine } from "@/server/curdMachine";
|
||||
import { withServerPromise } from "@/server/withServerPromise";
|
||||
import { auth } from "@clerk/nextjs";
|
||||
import { clerkClient } from "@clerk/nextjs/server";
|
||||
import slugify from "@sindresorhus/slugify";
|
||||
import { and, eq, isNull, or } from "drizzle-orm";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { redirect } from "next/navigation";
|
||||
import "server-only";
|
||||
import { validate as isValidUUID } from "uuid";
|
||||
import type { z } from "zod";
|
||||
|
||||
export async function createDeployments(
|
||||
workflow_id: string,
|
||||
version_id: string,
|
||||
machine_id: string,
|
||||
environment: DeploymentType["environment"],
|
||||
environment: DeploymentType["environment"]
|
||||
) {
|
||||
const { userId, orgId } = auth();
|
||||
if (!userId) throw new Error("No user id");
|
||||
@@ -32,7 +30,7 @@ export async function createDeployments(
|
||||
const existingDeployment = await db.query.deploymentsTable.findFirst({
|
||||
where: and(
|
||||
eq(deploymentsTable.workflow_id, workflow_id),
|
||||
eq(deploymentsTable.environment, environment),
|
||||
eq(deploymentsTable.environment, environment)
|
||||
),
|
||||
});
|
||||
|
||||
@@ -47,27 +45,6 @@ export async function createDeployments(
|
||||
})
|
||||
.where(eq(deploymentsTable.id, existingDeployment.id));
|
||||
} else {
|
||||
const workflow = await db.query.workflowTable.findFirst({
|
||||
where: eq(workflowTable.id, workflow_id),
|
||||
with: {
|
||||
user: {
|
||||
columns: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!workflow) throw new Error("No workflow found");
|
||||
|
||||
const userName = workflow.org_id
|
||||
? await clerkClient.organizations
|
||||
.getOrganization({
|
||||
organizationId: workflow.org_id,
|
||||
})
|
||||
.then((x) => x.name)
|
||||
: workflow.user.name;
|
||||
|
||||
await db.insert(deploymentsTable).values({
|
||||
user_id: userId,
|
||||
workflow_id,
|
||||
@@ -75,8 +52,6 @@ export async function createDeployments(
|
||||
machine_id,
|
||||
environment,
|
||||
org_id: orgId,
|
||||
// only create share slug if this is public share
|
||||
share_slug: environment == "public-share" ? slugify(`${userName} ${workflow.name}`) : null
|
||||
});
|
||||
}
|
||||
revalidatePath(`/${workflow_id}`);
|
||||
@@ -93,7 +68,7 @@ export async function findAllDeployments() {
|
||||
where: and(
|
||||
orgId
|
||||
? eq(workflowTable.org_id, orgId)
|
||||
: and(eq(workflowTable.user_id, userId), isNull(workflowTable.org_id)),
|
||||
: and(eq(workflowTable.user_id, userId), isNull(workflowTable.org_id))
|
||||
),
|
||||
columns: {
|
||||
name: true,
|
||||
@@ -122,9 +97,7 @@ export async function findSharedDeployment(workflow_id: string) {
|
||||
const deploymentData = await db.query.deploymentsTable.findFirst({
|
||||
where: and(
|
||||
eq(deploymentsTable.environment, "public-share"),
|
||||
isValidUUID(workflow_id)
|
||||
? eq(deploymentsTable.id, workflow_id)
|
||||
: eq(deploymentsTable.share_slug, workflow_id),
|
||||
eq(deploymentsTable.id, workflow_id)
|
||||
),
|
||||
with: {
|
||||
user: true,
|
||||
@@ -145,20 +118,15 @@ export async function findSharedDeployment(workflow_id: string) {
|
||||
|
||||
export const removePublicShareDeployment = withServerPromise(
|
||||
async (deployment_id: string) => {
|
||||
const [removed] = await db
|
||||
await db
|
||||
.delete(deploymentsTable)
|
||||
.where(
|
||||
and(
|
||||
eq(deploymentsTable.environment, "public-share"),
|
||||
eq(deploymentsTable.id, deployment_id),
|
||||
),
|
||||
)
|
||||
.returning();
|
||||
|
||||
// revalidatePath(
|
||||
// `/workflows/${removed.workflow_id}`
|
||||
// )
|
||||
},
|
||||
eq(deploymentsTable.id, deployment_id)
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const cloneWorkflow = withServerPromise(
|
||||
@@ -166,7 +134,7 @@ export const cloneWorkflow = withServerPromise(
|
||||
const deployment = await db.query.deploymentsTable.findFirst({
|
||||
where: and(
|
||||
eq(deploymentsTable.environment, "public-share"),
|
||||
eq(deploymentsTable.id, deployment_id),
|
||||
eq(deploymentsTable.id, deployment_id)
|
||||
),
|
||||
with: {
|
||||
version: true,
|
||||
@@ -196,14 +164,14 @@ export const cloneWorkflow = withServerPromise(
|
||||
return {
|
||||
message: "Successfully cloned workflow",
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const cloneMachine = withServerPromise(async (deployment_id: string) => {
|
||||
const deployment = await db.query.deploymentsTable.findFirst({
|
||||
where: and(
|
||||
eq(deploymentsTable.environment, "public-share"),
|
||||
eq(deploymentsTable.id, deployment_id),
|
||||
eq(deploymentsTable.id, deployment_id)
|
||||
),
|
||||
with: {
|
||||
machine: true,
|
||||
@@ -241,17 +209,15 @@ export async function findUserShareDeployment(share_id: string) {
|
||||
.from(deploymentsTable)
|
||||
.where(
|
||||
and(
|
||||
isValidUUID(share_id)
|
||||
? eq(deploymentsTable.id, share_id)
|
||||
: eq(deploymentsTable.share_slug, share_id),
|
||||
eq(deploymentsTable.id, share_id),
|
||||
eq(deploymentsTable.environment, "public-share"),
|
||||
orgId
|
||||
? eq(deploymentsTable.org_id, orgId)
|
||||
: and(
|
||||
eq(deploymentsTable.user_id, userId),
|
||||
isNull(deploymentsTable.org_id),
|
||||
),
|
||||
),
|
||||
eq(deploymentsTable.user_id, userId),
|
||||
isNull(deploymentsTable.org_id)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (!deployment) throw new Error("No deployment found");
|
||||
@@ -277,11 +243,11 @@ export const updateSharePageInfo = withServerPromise(
|
||||
.where(
|
||||
and(
|
||||
eq(deploymentsTable.environment, "public-share"),
|
||||
eq(deploymentsTable.id, id),
|
||||
),
|
||||
eq(deploymentsTable.id, id)
|
||||
)
|
||||
)
|
||||
.returning();
|
||||
|
||||
return { message: "Info Updated" };
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { getMachineById } from "@/server/curdMachine";
|
||||
import { auth } from "@clerk/nextjs";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { getOrgOrUserDisplayName } from "@/server/getOrgOrUserDisplayName";
|
||||
import { withServerPromise } from "@/server/withServerPromise";
|
||||
import "server-only";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export const editWorkflowOnMachine = withServerPromise(
|
||||
async (workflow_version_id: string, machine_id: string) => {
|
||||
const { userId, orgId } = auth();
|
||||
|
||||
const headersList = headers();
|
||||
const host = headersList.get("host") || "";
|
||||
const protocol = headersList.get("x-forwarded-proto") || "";
|
||||
const domain = `${protocol}://${host}`;
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("No user id");
|
||||
}
|
||||
|
||||
const machine = await getMachineById(machine_id);
|
||||
|
||||
const expireTime = "1w";
|
||||
const token = jwt.sign(
|
||||
{ user_id: userId, org_id: orgId },
|
||||
process.env.JWT_SECRET!,
|
||||
{
|
||||
expiresIn: expireTime,
|
||||
},
|
||||
);
|
||||
|
||||
const userName = await getOrgOrUserDisplayName(orgId, userId);
|
||||
|
||||
let endpoint = machine.endpoint;
|
||||
|
||||
if (machine.type === "comfy-deploy-serverless") {
|
||||
endpoint = machine.endpoint.replace("comfyui-api", "comfyui-app");
|
||||
}
|
||||
|
||||
return `${endpoint}?workflow_version_id=${encodeURIComponent(
|
||||
workflow_version_id,
|
||||
)}&auth_token=${encodeURIComponent(token)}&org_display=${encodeURIComponent(
|
||||
userName,
|
||||
)}&origin=${encodeURIComponent(domain)}`;
|
||||
},
|
||||
);
|
||||
@@ -16,42 +16,28 @@ export async function findAllRuns({
|
||||
offset = 0,
|
||||
}: RunsSearchTypes) {
|
||||
return await db.query.workflowRunsTable.findMany({
|
||||
where: eq(workflowRunsTable.workflow_id, workflow_id),
|
||||
orderBy: desc(workflowRunsTable.created_at),
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
extras: {
|
||||
number: sql<number>`row_number() over (order by created_at)`.as(
|
||||
"number",
|
||||
),
|
||||
total: sql<number>`count(*) over ()`.as("total"),
|
||||
duration:
|
||||
sql<number>`(extract(epoch from ended_at) - extract(epoch from created_at))`.as(
|
||||
"duration",
|
||||
),
|
||||
cold_start_duration:
|
||||
sql<number>`(extract(epoch from started_at) - extract(epoch from created_at))`.as(
|
||||
"cold_start_duration",
|
||||
),
|
||||
run_duration:
|
||||
sql<number>`(extract(epoch from ended_at) - extract(epoch from started_at))`.as(
|
||||
"run_duration",
|
||||
),
|
||||
},
|
||||
with: {
|
||||
machine: {
|
||||
columns: {
|
||||
name: true,
|
||||
endpoint: true,
|
||||
},
|
||||
},
|
||||
version: {
|
||||
columns: {
|
||||
version: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
where: eq(workflowRunsTable.workflow_id, workflow_id),
|
||||
orderBy: desc(workflowRunsTable.created_at),
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
extras: {
|
||||
number: sql<number>`row_number() over (order by created_at)`.as("number"),
|
||||
total: sql<number>`count(*) over ()`.as("total"),
|
||||
},
|
||||
with: {
|
||||
machine: {
|
||||
columns: {
|
||||
name: true,
|
||||
endpoint: true,
|
||||
},
|
||||
},
|
||||
version: {
|
||||
columns: {
|
||||
version: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function findAllRunsWithCounts(props: RunsSearchTypes) {
|
||||
|
||||
@@ -4,10 +4,8 @@ import {
|
||||
workflowTable,
|
||||
workflowVersionTable,
|
||||
} from "@/db/schema";
|
||||
import { APIKeyUserType } from "@/server/APIKeyBodyRequest";
|
||||
import { auth } from "@clerk/nextjs";
|
||||
import { and, desc, eq, isNull } from "drizzle-orm";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export async function getAllUserWorkflow() {
|
||||
const { userId, orgId } = await auth();
|
||||
@@ -53,29 +51,3 @@ export async function getAllUserWorkflow() {
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
export async function getWorkflowVersion(
|
||||
apiUser: APIKeyUserType,
|
||||
version_id: string,
|
||||
) {
|
||||
const { org_id, user_id } = apiUser;
|
||||
|
||||
if (!user_id) {
|
||||
throw new Error("No user id");
|
||||
}
|
||||
|
||||
const parentWorkflow = await db.query.workflowTable.findFirst({
|
||||
where:
|
||||
org_id != undefined
|
||||
? eq(workflowTable.org_id, org_id)
|
||||
: and(eq(workflowTable.user_id, user_id), isNull(workflowTable.org_id)),
|
||||
});
|
||||
|
||||
if (!parentWorkflow) {
|
||||
throw new Error("No workflow found");
|
||||
}
|
||||
|
||||
return db.query.workflowVersionTable.findFirst({
|
||||
where: eq(workflowVersionTable.id, version_id),
|
||||
});
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { db } from "@/db/db";
|
||||
import { usersTable } from "@/db/schema";
|
||||
import { clerkClient } from "@clerk/nextjs";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export async function getOrgOrUserDisplayName(
|
||||
orgId: string | undefined | null,
|
||||
userId: string,
|
||||
) {
|
||||
return orgId
|
||||
? await clerkClient.organizations
|
||||
.getOrganization({
|
||||
organizationId: orgId,
|
||||
})
|
||||
.then((x) => x.name)
|
||||
: (await db.select().from(usersTable).where(eq(usersTable.id, userId)))[0]
|
||||
.name;
|
||||
}
|
||||
@@ -49,26 +49,24 @@ export async function getRunsData(run_id: string, user?: APIKeyUserType) {
|
||||
for (let i = 0; i < data.outputs.length; i++) {
|
||||
const output = data.outputs[i];
|
||||
|
||||
if (output.data?.images !== undefined)
|
||||
replaceUrls(output.data?.images, data.id);
|
||||
|
||||
if (output.data?.files !== undefined)
|
||||
replaceUrls(output.data?.files, data.id);
|
||||
|
||||
if (output.data?.gifs !== undefined)
|
||||
replaceUrls(output.data?.gifs, data.id);
|
||||
if (output.data?.images !== undefined) {
|
||||
for (let j = 0; j < output.data?.images.length; j++) {
|
||||
const element = output.data?.images[j];
|
||||
element.url = replaceCDNUrl(
|
||||
`${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${data.id}/${element.filename}`
|
||||
);
|
||||
}
|
||||
} else if (output.data?.files !== undefined) {
|
||||
for (let j = 0; j < output.data?.files.length; j++) {
|
||||
const element = output.data?.files[j];
|
||||
element.url = replaceCDNUrl(
|
||||
`${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${data.id}/${element.filename}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function replaceUrls(dataType: any[], dataId: string) {
|
||||
for (let j = 0; j < dataType.length; j++) {
|
||||
const element = dataType[j];
|
||||
element.url = replaceCDNUrl(
|
||||
`${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${dataId}/${element.filename}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user