diff --git a/.env.node.example b/.env.node.example
index fb986f1..6e0ebc5 100644
--- a/.env.node.example
+++ b/.env.node.example
@@ -4,10 +4,10 @@
DATABASE_URL="file:./db.sqlite"
# File Storage
-FILE_STORAGE="base64" # Options: "base64"(default), "local", "r2"
+FILE_STORAGE="base64" # Options: "base64"(default), "disk", "r2"
# Local File Storage Configuration
-FILE_STORAGE_LOCAL_PATH=".files" # Path to store files locally, default is .files directory
+# FILE_STORAGE_DISK_PATH=".files" # Path to store files locally, default is .files directory
# For more Environment Variables, see wrangler.toml [vars]
# ...
\ No newline at end of file
diff --git a/src/app/components/dev/DatabaseStudio.tsx b/src/app/components/dev/DatabaseStudio.tsx
index d1f097c..91dee12 100644
--- a/src/app/components/dev/DatabaseStudio.tsx
+++ b/src/app/components/dev/DatabaseStudio.tsx
@@ -1,9 +1,6 @@
import { Badge } from "@/app/components/ui/badge";
import { Button } from "@/app/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/app/components/ui/card";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/app/components/ui/dialog";
-import { ScrollArea } from "@/app/components/ui/scroll-area";
-import { Separator } from "@/app/components/ui/separator";
import { Textarea } from "@/app/components/ui/textarea";
import { getDb } from "@/app/lib/db-client";
import { Database } from "lucide-react";
@@ -106,85 +103,6 @@ export function DatabaseStudio() {
setIsOpen(false);
};
- const renderTable = () => {
- if (!result?.columns || !result?.rows) return null;
-
- return (
-
-
-
-
-
- {result.columns.map((column) => (
- |
- {column}
- |
- ))}
-
-
-
- {result.rows.map((row, rowIndex) => (
-
- {result.columns!.map((column) => (
- |
- {row[column] !== null && row[column] !== undefined ? (
- String(row[column])
- ) : (
- NULL
- )}
- |
- ))}
-
- ))}
-
-
-
-
- );
- };
-
- const renderResult = () => {
- if (!result) return null;
-
- return (
-
-
- Query Results
-
- {result.executionTime && {result.executionTime.toFixed(2)}ms}
-
-
-
-
- {result.error ? (
-
-
Error:
-
{result.error}
-
- ) : result.columns && result.rows ? (
-
-
- {result.rows.length} rows
- {result.columns.length} columns
-
- {renderTable()}
-
- ) : (
-
-
- {typeof result.changes === "number" && Affected rows: {result.changes}}
- {result.lastInsertRowid && Insert ID: {String(result.lastInsertRowid)}}
-
-
Query execution completed
-
- )}
-
-
- );
- };
-
return (
<>
{/* Floating Button */}
@@ -207,7 +125,7 @@ export function DatabaseStudio() {
-
+
{/* SQL Input Area */}
@@ -254,7 +172,7 @@ export function DatabaseStudio() {
{/* Results Display Area - Fill remaining space */}
{result ? (
-
+
{/* Results Header */}
@@ -269,7 +187,7 @@ export function DatabaseStudio() {
{/* Results Content - Fill remaining space */}
-
+
{result.error ? (
@@ -289,7 +207,7 @@ export function DatabaseStudio() {
{/* Table - Fill remaining space */}
-
+
@@ -335,8 +253,7 @@ export function DatabaseStudio() {
))}
-
-
+
) : (
diff --git a/src/server/ai/provider/cloudflare.ts b/src/server/ai/provider/cloudflare.ts
index 47fd073..99a1c48 100644
--- a/src/server/ai/provider/cloudflare.ts
+++ b/src/server/ai/provider/cloudflare.ts
@@ -27,7 +27,7 @@ const createFormData = (params: any, model: CloudflareAiModel, request: TypixGen
// Append images with numbered parameter names
for (let i = 0; i < Math.min(images.length, maxInputImages); i++) {
- const imageBlob = base64ToBlob(images[i]!);
+ const imageBlob = base64ToBlob(dataURItoBase64(images[i]!));
form.append(`input_image_${i}`, imageBlob);
}
}
@@ -76,7 +76,7 @@ const generateSingle = async (request: TypixGenerateRequest, settings: ApiProvid
params.height = size?.height;
}
if (genType === "i2i") {
- params.image_b64 = request.images![0]!;
+ params.image_b64 = dataURItoBase64(request.images![0]!);
}
// Built-in Cloudflare Worker AI
diff --git a/src/server/lib/util.ts b/src/server/lib/util.ts
index 7a67f9f..bfffa81 100644
--- a/src/server/lib/util.ts
+++ b/src/server/lib/util.ts
@@ -13,7 +13,7 @@ export function base64ToBlob(base64: string, mimeType = "image/png") {
}
export function dataURItoBase64(dataURI: string) {
- return dataURI.split(",")[1];
+ return dataURI.split(",")[1]!;
}
export async function readableStreamToDataURI(stream: ReadableStream
, fmt = "png") {
diff --git a/src/server/service/file/storage.ts b/src/server/service/file/storage.ts
index c4e2452..434da6f 100644
--- a/src/server/service/file/storage.ts
+++ b/src/server/service/file/storage.ts
@@ -1,6 +1,6 @@
import { type Storage, files } from "@/server/db/schemas";
import { inBrowser } from "@/server/lib/env";
-import { fetchUrlToDataURI } from "@/server/lib/util";
+import { base64ToDataURI, fetchUrlToDataURI } from "@/server/lib/util";
import { and, eq } from "drizzle-orm";
import { getContext } from "../context";
@@ -120,7 +120,7 @@ export const getFileMetadata = async (fileId: string, userId: string) => {
};
/**
- * Get file base64-encoded string
+ * Get file base64 data URL
* @param fileId File ID to get data for
* @param userId User ID to check access
* @param redirect
@@ -138,10 +138,11 @@ export const getFileData = async (fileId: string, userId: string) => {
switch (metadata.protocol) {
case "data:":
- return metadata.accessUrl.split(",")[1]!; // Return base64 part only
+ return metadata.accessUrl;
case "file:": {
const fs = await import("node:fs/promises");
- return await fs.readFile(metadata.accessUrl, "base64");
+ const fileSuffix = metadata.accessUrl.split(".").pop();
+ return base64ToDataURI(await fs.readFile(metadata.accessUrl, "base64"), fileSuffix);
}
default:
return await fetchUrlToDataURI(metadata.accessUrl);
diff --git a/wrangler.toml b/wrangler.toml
index a5ec769..f73860f 100644
--- a/wrangler.toml
+++ b/wrangler.toml
@@ -30,7 +30,7 @@ binding = "AI"
# Authenticated users benefit from cross-device data sync and server-side data persistence.
# Provides the best of both worlds: instant local access with optional cloud features.
MODE = "client"
-GOOGLE_ANALYTICS_ID = "G-0T65G1J5DT"
+# GOOGLE_ANALYTICS_ID = "G-0T65G1J5DT"
# Authentication configuration, only for mixed mode
#