dynamic worker routes based on env

This commit is contained in:
Ishaan Dey 2024-05-26 18:37:36 -07:00
parent 6285a68102
commit 6376493ae7
17 changed files with 427 additions and 260 deletions

View File

@ -1,16 +1,18 @@
// import type { DrizzleD1Database } from "drizzle-orm/d1";
import { drizzle } from "drizzle-orm/d1";
import { json } from "itty-router-extras";
import { ZodError, z } from "zod";
import { drizzle } from "drizzle-orm/d1"
import { json } from "itty-router-extras"
import { ZodError, z } from "zod"
import { user, sandbox, usersToSandboxes } from "./schema";
import * as schema from "./schema";
import { and, eq, sql } from "drizzle-orm";
import { user, sandbox, usersToSandboxes } from "./schema"
import * as schema from "./schema"
import { and, eq, sql } from "drizzle-orm"
export interface Env {
DB: D1Database;
STORAGE: any;
KV: KVNamespace;
DB: D1Database
STORAGE: any
KV: KVNamespace
KEY: string
STORAGE_WORKER_URL: string
}
// https://github.com/drizzle-team/drizzle-orm/tree/main/examples/cloudflare-d1
@ -19,130 +21,163 @@ export interface Env {
// npx wrangler d1 execute d1-sandbox --local --file=./drizzle/<FILE>
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const success = new Response("Success", { status: 200 });
const invalidRequest = new Response("Invalid Request", { status: 400 });
const notFound = new Response("Not Found", { status: 404 });
const methodNotAllowed = new Response("Method Not Allowed", { status: 405 });
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const success = new Response("Success", { status: 200 })
const invalidRequest = new Response("Invalid Request", { status: 400 })
const notFound = new Response("Not Found", { status: 404 })
const methodNotAllowed = new Response("Method Not Allowed", { status: 405 })
const url = new URL(request.url);
const path = url.pathname;
const method = request.method;
const url = new URL(request.url)
const path = url.pathname
const method = request.method
const db = drizzle(env.DB, { schema });
if (request.headers.get("Authorization") !== env.KEY) {
return new Response("Unauthorized", { status: 401 })
}
const db = drizzle(env.DB, { schema })
if (path === "/api/session") {
if (method === "PUT") {
const body = await request.json();
const body = await request.json()
const schema = z.object({
userId: z.string(),
sandboxId: z.string(),
});
})
const { userId, sandboxId } = schema.parse(body);
const { userId, sandboxId } = schema.parse(body)
await env.KV.put(userId, sandboxId);
await env.KV.put(userId, sandboxId)
return success;
return success
} else if (method === "GET") {
const params = url.searchParams;
const params = url.searchParams
if (params.has("id")) {
const id = params.get("id") as string;
const sandboxId = await env.KV.get(id);
return json({ sandboxId });
} else return invalidRequest;
const id = params.get("id") as string
const sandboxId = await env.KV.get(id)
return json({ sandboxId })
} else return invalidRequest
} else if (method === "DELETE") {
const params = url.searchParams;
const params = url.searchParams
if (params.has("id")) {
const id = params.get("id") as string;
await env.KV.delete(id);
return success;
} else return invalidRequest;
} else return methodNotAllowed;
const id = params.get("id") as string
await env.KV.delete(id)
return success
} else return invalidRequest
} else return methodNotAllowed
} else if (path === "/api/sandbox") {
if (method === "GET") {
const params = url.searchParams;
const params = url.searchParams
if (params.has("id")) {
const id = params.get("id") as string;
const id = params.get("id") as string
const res = await db.query.sandbox.findFirst({
where: (sandbox, { eq }) => eq(sandbox.id, id),
with: {
usersToSandboxes: true,
},
});
return json(res ?? {});
})
return json(res ?? {})
} else {
const res = await db.select().from(sandbox).all();
return json(res ?? {});
const res = await db.select().from(sandbox).all()
return json(res ?? {})
}
} else if (method === "DELETE") {
const params = url.searchParams;
const params = url.searchParams
if (params.has("id")) {
const id = params.get("id") as string;
await db.delete(usersToSandboxes).where(eq(usersToSandboxes.sandboxId, id));
await db.delete(sandbox).where(eq(sandbox.id, id));
const id = params.get("id") as string
await db
.delete(usersToSandboxes)
.where(eq(usersToSandboxes.sandboxId, id))
await db.delete(sandbox).where(eq(sandbox.id, id))
const deleteStorageRequest = new Request("https://storage.ishaan1013.workers.dev/api/project", {
method: "DELETE",
body: JSON.stringify({ sandboxId: id }),
headers: { "Content-Type": "application/json" },
});
const deleteStorageRes = await env.STORAGE.fetch(deleteStorageRequest);
const deleteStorageRequest = new Request(
`${env.STORAGE_WORKER_URL}/api/project`,
{
method: "DELETE",
body: JSON.stringify({ sandboxId: id }),
headers: {
"Content-Type": "application/json",
Authorization: `${env.KEY}`,
},
}
)
await env.STORAGE.fetch(deleteStorageRequest)
return success;
return success
} else {
return invalidRequest;
return invalidRequest
}
} else if (method === "POST") {
const postSchema = z.object({
id: z.string(),
name: z.string().optional(),
visibility: z.enum(["public", "private"]).optional(),
});
})
const body = await request.json();
const { id, name, visibility } = postSchema.parse(body);
const sb = await db.update(sandbox).set({ name, visibility }).where(eq(sandbox.id, id)).returning().get();
const body = await request.json()
const { id, name, visibility } = postSchema.parse(body)
const sb = await db
.update(sandbox)
.set({ name, visibility })
.where(eq(sandbox.id, id))
.returning()
.get()
return success;
return success
} else if (method === "PUT") {
const initSchema = z.object({
type: z.enum(["react", "node"]),
name: z.string(),
userId: z.string(),
visibility: z.enum(["public", "private"]),
});
})
const body = await request.json();
const { type, name, userId, visibility } = initSchema.parse(body);
const body = await request.json()
const { type, name, userId, visibility } = initSchema.parse(body)
const allSandboxes = await db.select().from(sandbox).all();
const allSandboxes = await db.select().from(sandbox).all()
if (allSandboxes.length >= 8) {
return new Response("You reached the maximum # of sandboxes.", { status: 400 });
return new Response("You reached the maximum # of sandboxes.", {
status: 400,
})
}
const sb = await db.insert(sandbox).values({ type, name, userId, visibility, createdAt: new Date() }).returning().get();
const sb = await db
.insert(sandbox)
.values({ type, name, userId, visibility, createdAt: new Date() })
.returning()
.get()
const initStorageRequest = new Request("https://storage.ishaan1013.workers.dev/api/init", {
method: "POST",
body: JSON.stringify({ sandboxId: sb.id, type }),
headers: { "Content-Type": "application/json" },
});
const initStorageRequest = new Request(
`${env.STORAGE_WORKER_URL}/api/init`,
{
method: "POST",
body: JSON.stringify({ sandboxId: sb.id, type }),
headers: {
"Content-Type": "application/json",
Authorization: `${env.KEY}`,
},
}
)
await env.STORAGE.fetch(initStorageRequest);
await env.STORAGE.fetch(initStorageRequest)
return new Response(sb.id, { status: 200 });
return new Response(sb.id, { status: 200 })
} else {
return methodNotAllowed;
return methodNotAllowed
}
} else if (path === "/api/sandbox/share") {
if (method === "GET") {
const params = url.searchParams;
const params = url.searchParams
if (params.has("id")) {
const id = params.get("id") as string;
const id = params.get("id") as string
const res = await db.query.usersToSandboxes.findMany({
where: (uts, { eq }) => eq(uts.userId, id),
});
})
const owners = await Promise.all(
res.map(async (r) => {
@ -151,22 +186,28 @@ export default {
with: {
author: true,
},
});
if (!sb) return;
return { id: sb.id, name: sb.name, type: sb.type, author: sb.author.name, sharedOn: r.sharedOn };
})
if (!sb) return
return {
id: sb.id,
name: sb.name,
type: sb.type,
author: sb.author.name,
sharedOn: r.sharedOn,
}
})
);
)
return json(owners ?? {});
} else return invalidRequest;
return json(owners ?? {})
} else return invalidRequest
} else if (method === "POST") {
const shareSchema = z.object({
sandboxId: z.string(),
email: z.string(),
});
})
const body = await request.json();
const { sandboxId, email } = shareSchema.parse(body);
const body = await request.json()
const { sandboxId, email } = shareSchema.parse(body)
const user = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.email, email),
@ -174,66 +215,78 @@ export default {
sandbox: true,
usersToSandboxes: true,
},
});
})
if (!user) {
return new Response("No user associated with email.", { status: 400 });
return new Response("No user associated with email.", { status: 400 })
}
if (user.sandbox.find((sb) => sb.id === sandboxId)) {
return new Response("Cannot share with yourself!", { status: 400 });
return new Response("Cannot share with yourself!", { status: 400 })
}
if (user.usersToSandboxes.find((uts) => uts.sandboxId === sandboxId)) {
return new Response("User already has access.", { status: 400 });
return new Response("User already has access.", { status: 400 })
}
await db.insert(usersToSandboxes).values({ userId: user.id, sandboxId, sharedOn: new Date() }).get();
await db
.insert(usersToSandboxes)
.values({ userId: user.id, sandboxId, sharedOn: new Date() })
.get()
return success;
return success
} else if (method === "DELETE") {
const deleteShareSchema = z.object({
sandboxId: z.string(),
userId: z.string(),
});
})
const body = await request.json();
const { sandboxId, userId } = deleteShareSchema.parse(body);
const body = await request.json()
const { sandboxId, userId } = deleteShareSchema.parse(body)
await db.delete(usersToSandboxes).where(and(eq(usersToSandboxes.userId, userId), eq(usersToSandboxes.sandboxId, sandboxId)));
await db
.delete(usersToSandboxes)
.where(
and(
eq(usersToSandboxes.userId, userId),
eq(usersToSandboxes.sandboxId, sandboxId)
)
)
return success;
} else return methodNotAllowed;
return success
} else return methodNotAllowed
} else if (path === "/api/sandbox/generate" && method === "POST") {
const generateSchema = z.object({
userId: z.string(),
});
const body = await request.json();
const { userId } = generateSchema.parse(body);
})
const body = await request.json()
const { userId } = generateSchema.parse(body)
const dbUser = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.id, userId),
});
})
if (!dbUser) {
return new Response("User not found.", { status: 400 });
return new Response("User not found.", { status: 400 })
}
if (dbUser.generations !== null && dbUser.generations >= 10) {
return new Response("You reached the maximum # of generations.", { status: 400 });
return new Response("You reached the maximum # of generations.", {
status: 400,
})
}
await db
.update(user)
.set({ generations: sql`${user.generations} + 1` })
.where(eq(user.id, userId))
.get();
.get()
return success;
return success
} else if (path === "/api/user") {
if (method === "GET") {
const params = url.searchParams;
const params = url.searchParams
if (params.has("id")) {
const id = params.get("id") as string;
const id = params.get("id") as string
const res = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.id, id),
with: {
@ -242,34 +295,38 @@ export default {
},
usersToSandboxes: true,
},
});
return json(res ?? {});
})
return json(res ?? {})
} else {
const res = await db.select().from(user).all();
return json(res ?? {});
const res = await db.select().from(user).all()
return json(res ?? {})
}
} else if (method === "POST") {
const userSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
});
})
const body = await request.json();
const { id, name, email } = userSchema.parse(body);
const body = await request.json()
const { id, name, email } = userSchema.parse(body)
const res = await db.insert(user).values({ id, name, email }).returning().get();
return json({ res });
const res = await db
.insert(user)
.values({ id, name, email })
.returning()
.get()
return json({ res })
} else if (method === "DELETE") {
const params = url.searchParams;
const params = url.searchParams
if (params.has("id")) {
const id = params.get("id") as string;
await db.delete(user).where(eq(user.id, id));
return success;
} else return invalidRequest;
const id = params.get("id") as string
await db.delete(user).where(eq(user.id, id))
return success
} else return invalidRequest
} else {
return methodNotAllowed;
return methodNotAllowed
}
} else return notFound;
} else return notFound
},
};
}

View File

@ -10,3 +10,7 @@ services = [{ binding = "STORAGE", service = "storage" }]
binding = "DB"
database_name = ""
database_id = ""
[vars]
KEY = ""
STORAGE_WORKER_URL = ""

View File

@ -1 +1,2 @@
PORT=4000
WORKERS_KEY=

View File

@ -70,7 +70,12 @@ io.use(async (socket, next) => {
const { sandboxId, userId } = parseQuery.data;
const dbUser = await fetch(
`https://database.ishaan1013.workers.dev/api/user?id=${userId}`
`${process.env.DATABASE_WORKER_URL}/api/user?id=${userId}`,
{
headers: {
Authorization: `${process.env.WORKERS_KEY}`,
},
}
);
const dbUserJSON = (await dbUser.json()) as User;
@ -400,11 +405,12 @@ io.on("connection", async (socket) => {
) => {
// Log code generation credit in DB
const fetchPromise = fetch(
`https://database.ishaan1013.workers.dev/api/sandbox/generate`,
`${process.env.DATABASE_WORKER_URL}/api/sandbox/generate`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.WORKERS_KEY}`,
},
body: JSON.stringify({
userId: data.userId,
@ -414,7 +420,7 @@ io.on("connection", async (socket) => {
// Generate code from cloudflare workers AI
const generateCodePromise = fetch(
`https://ai.ishaan1013.workers.dev/api?fileName=${fileName}&code=${code}&line=${line}&instructions=${instructions}`,
`${process.env.AI_WORKER_URL}/api?fileName=${fileName}&code=${code}&line=${line}&instructions=${instructions}`,
{
headers: {
"Content-Type": "application/json",

View File

@ -12,7 +12,12 @@ dotenv.config();
export const getSandboxFiles = async (id: string) => {
const res = await fetch(
`https://storage.ishaan1013.workers.dev/api?sandboxId=${id}`
`${process.env.STORAGE_WORKER_URL}/api?sandboxId=${id}`,
{
headers: {
Authorization: `${process.env.WORKERS_KEY}`,
},
}
);
const data: R2Files = await res.json();
@ -23,7 +28,12 @@ export const getSandboxFiles = async (id: string) => {
export const getFolder = async (folderId: string) => {
const res = await fetch(
`https://storage.ishaan1013.workers.dev/api?folderId=${folderId}`
`${process.env.STORAGE_WORKER_URL}/api?folderId=${folderId}`,
{
headers: {
Authorization: `${process.env.WORKERS_KEY}`,
},
}
);
const data: R2Files = await res.json();
@ -88,7 +98,12 @@ const processFiles = async (paths: string[], id: string) => {
const fetchFileContent = async (fileId: string): Promise<string> => {
try {
const fileRes = await fetch(
`https://storage.ishaan1013.workers.dev/api?fileId=${fileId}`
`${process.env.STORAGE_WORKER_URL}/api?fileId=${fileId}`,
{
headers: {
Authorization: `${process.env.WORKERS_KEY}`,
},
}
);
return await fileRes.text();
} catch (error) {
@ -98,10 +113,11 @@ const fetchFileContent = async (fileId: string): Promise<string> => {
};
export const createFile = async (fileId: string) => {
const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, {
const res = await fetch(`${process.env.STORAGE_WORKER_URL}/api`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.WORKERS_KEY}`,
},
body: JSON.stringify({ fileId }),
});
@ -113,10 +129,11 @@ export const renameFile = async (
newFileId: string,
data: string
) => {
const res = await fetch(`https://storage.ishaan1013.workers.dev/api/rename`, {
const res = await fetch(`${process.env.STORAGE_WORKER_URL}/api/rename`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.WORKERS_KEY}`,
},
body: JSON.stringify({ fileId, newFileId, data }),
});
@ -124,10 +141,11 @@ export const renameFile = async (
};
export const saveFile = async (fileId: string, data: string) => {
const res = await fetch(`https://storage.ishaan1013.workers.dev/api/save`, {
const res = await fetch(`${process.env.STORAGE_WORKER_URL}/api/save`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.WORKERS_KEY}`,
},
body: JSON.stringify({ fileId, data }),
});
@ -135,10 +153,11 @@ export const saveFile = async (fileId: string, data: string) => {
};
export const deleteFile = async (fileId: string) => {
const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, {
const res = await fetch(`${process.env.STORAGE_WORKER_URL}/api`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.WORKERS_KEY}`,
},
body: JSON.stringify({ fileId }),
});
@ -147,7 +166,12 @@ export const deleteFile = async (fileId: string) => {
export const getProjectSize = async (id: string) => {
const res = await fetch(
`https://storage.ishaan1013.workers.dev/api/size?sandboxId=${id}`
`${process.env.STORAGE_WORKER_URL}/api/size?sandboxId=${id}`,
{
headers: {
Authorization: `${process.env.WORKERS_KEY}`,
},
}
);
return (await res.json()).size;
};

View File

@ -1,150 +1,159 @@
import { z } from 'zod';
import startercode from './startercode';
import { z } from "zod"
import startercode from "./startercode"
export interface Env {
R2: R2Bucket;
R2: R2Bucket
KEY: string
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const success = new Response('Success', { status: 200 });
const invalidRequest = new Response('Invalid Request', { status: 400 });
const notFound = new Response('Not Found', { status: 404 });
const methodNotAllowed = new Response('Method Not Allowed', { status: 405 });
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const success = new Response("Success", { status: 200 })
const invalidRequest = new Response("Invalid Request", { status: 400 })
const notFound = new Response("Not Found", { status: 404 })
const methodNotAllowed = new Response("Method Not Allowed", { status: 405 })
const url = new URL(request.url);
const path = url.pathname;
const method = request.method;
if (request.headers.get("Authorization") !== env.KEY) {
return new Response("Unauthorized", { status: 401 })
}
if (path === '/api/project' && method === 'DELETE') {
const url = new URL(request.url)
const path = url.pathname
const method = request.method
if (path === "/api/project" && method === "DELETE") {
const deleteSchema = z.object({
sandboxId: z.string(),
});
})
const body = await request.json();
const { sandboxId } = deleteSchema.parse(body);
const body = await request.json()
const { sandboxId } = deleteSchema.parse(body)
const res = await env.R2.list({ prefix: 'projects/' + sandboxId });
const res = await env.R2.list({ prefix: "projects/" + sandboxId })
// delete all files
await Promise.all(
res.objects.map(async (file) => {
await env.R2.delete(file.key);
await env.R2.delete(file.key)
})
);
)
return success;
} else if (path === '/api/size' && method === 'GET') {
const params = url.searchParams;
const sandboxId = params.get('sandboxId');
return success
} else if (path === "/api/size" && method === "GET") {
const params = url.searchParams
const sandboxId = params.get("sandboxId")
if (sandboxId) {
const res = await env.R2.list({ prefix: `projects/${sandboxId}` });
const res = await env.R2.list({ prefix: `projects/${sandboxId}` })
// sum up the size of all files
let size = 0;
let size = 0
for (const file of res.objects) {
size += file.size;
size += file.size
}
return new Response(JSON.stringify({ size }), { status: 200 });
} else return invalidRequest;
} else if (path === '/api') {
if (method === 'GET') {
const params = url.searchParams;
const sandboxId = params.get('sandboxId');
const folderId = params.get('folderId');
const fileId = params.get('fileId');
return new Response(JSON.stringify({ size }), { status: 200 })
} else return invalidRequest
} else if (path === "/api") {
if (method === "GET") {
const params = url.searchParams
const sandboxId = params.get("sandboxId")
const folderId = params.get("folderId")
const fileId = params.get("fileId")
if (sandboxId) {
const res = await env.R2.list({ prefix: `projects/${sandboxId}` });
return new Response(JSON.stringify(res), { status: 200 });
const res = await env.R2.list({ prefix: `projects/${sandboxId}` })
return new Response(JSON.stringify(res), { status: 200 })
} else if (folderId) {
const res = await env.R2.list({ prefix: folderId });
return new Response(JSON.stringify(res), { status: 200 });
const res = await env.R2.list({ prefix: folderId })
return new Response(JSON.stringify(res), { status: 200 })
} else if (fileId) {
const obj = await env.R2.get(fileId);
const obj = await env.R2.get(fileId)
if (obj === null) {
return new Response(`${fileId} not found`, { status: 404 });
return new Response(`${fileId} not found`, { status: 404 })
}
const headers = new Headers();
headers.set('etag', obj.httpEtag);
obj.writeHttpMetadata(headers);
const headers = new Headers()
headers.set("etag", obj.httpEtag)
obj.writeHttpMetadata(headers)
const text = await obj.text();
const text = await obj.text()
return new Response(text, {
headers,
});
} else return invalidRequest;
} else if (method === 'POST') {
})
} else return invalidRequest
} else if (method === "POST") {
const createSchema = z.object({
fileId: z.string(),
});
})
const body = await request.json();
const { fileId } = createSchema.parse(body);
const body = await request.json()
const { fileId } = createSchema.parse(body)
await env.R2.put(fileId, '');
await env.R2.put(fileId, "")
return success;
} else if (method === 'DELETE') {
return success
} else if (method === "DELETE") {
const deleteSchema = z.object({
fileId: z.string(),
});
})
const body = await request.json();
const { fileId } = deleteSchema.parse(body);
const body = await request.json()
const { fileId } = deleteSchema.parse(body)
await env.R2.delete(fileId);
await env.R2.delete(fileId)
return success;
} else return methodNotAllowed;
} else if (path === '/api/rename' && method === 'POST') {
return success
} else return methodNotAllowed
} else if (path === "/api/rename" && method === "POST") {
const renameSchema = z.object({
fileId: z.string(),
newFileId: z.string(),
data: z.string(),
});
})
const body = await request.json();
const { fileId, newFileId, data } = renameSchema.parse(body);
const body = await request.json()
const { fileId, newFileId, data } = renameSchema.parse(body)
await env.R2.delete(fileId);
await env.R2.put(newFileId, data);
await env.R2.delete(fileId)
await env.R2.put(newFileId, data)
return success;
} else if (path === '/api/save' && method === 'POST') {
return success
} else if (path === "/api/save" && method === "POST") {
const renameSchema = z.object({
fileId: z.string(),
data: z.string(),
});
})
const body = await request.json();
const { fileId, data } = renameSchema.parse(body);
const body = await request.json()
const { fileId, data } = renameSchema.parse(body)
await env.R2.put(fileId, data);
await env.R2.put(fileId, data)
return success;
} else if (path === '/api/init' && method === 'POST') {
return success
} else if (path === "/api/init" && method === "POST") {
const initSchema = z.object({
sandboxId: z.string(),
type: z.enum(['react', 'node']),
});
type: z.enum(["react", "node"]),
})
const body = await request.json();
const { sandboxId, type } = initSchema.parse(body);
const body = await request.json()
const { sandboxId, type } = initSchema.parse(body)
console.log(startercode[type]);
console.log(startercode[type])
await Promise.all(
startercode[type].map(async (file) => {
await env.R2.put(`projects/${sandboxId}/${file.name}`, file.body);
await env.R2.put(`projects/${sandboxId}/${file.name}`, file.body)
})
);
)
return success;
return success
} else {
return notFound;
return notFound
}
},
};
}

View File

@ -11,3 +11,6 @@ workers_dev = true
binding = 'R2'
bucket_name = ''
preview_bucket_name = ''
[vars]
KEY = ''

View File

@ -4,6 +4,10 @@ NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY=
LIVEBLOCKS_SECRET_KEY=
NEXT_PUBLIC_SERVER_PORT=4000
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_DATABASE_WORKER_URL=
NEXT_PUBLIC_STORAGE_WORKER_URL=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up

View File

@ -11,7 +11,12 @@ export const revalidate = 0
const getUserData = async (id: string) => {
const userRes = await fetch(
`https://database.ishaan1013.workers.dev/api/user?id=${id}`
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user?id=${id}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
const userData: User = await userRes.json()
return userData
@ -19,7 +24,12 @@ const getUserData = async (id: string) => {
const getSandboxData = async (id: string) => {
const sandboxRes = await fetch(
`https://database.ishaan1013.workers.dev/api/sandbox?id=${id}`
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox?id=${id}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
const sandboxData: Sandbox = await sandboxRes.json()
return sandboxData
@ -33,7 +43,12 @@ const getSharedUsers = async (usersToSandboxes: UsersToSandboxes[]) => {
const shared = await Promise.all(
usersToSandboxes.map(async (user) => {
const userRes = await fetch(
`https://database.ishaan1013.workers.dev/api/user?id=${user.userId}`
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user?id=${user.userId}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
const userData: User = await userRes.json()
return { id: userData.id, name: userData.name }

View File

@ -12,12 +12,22 @@ export default async function DashboardPage() {
}
const userRes = await fetch(
`https://database.ishaan1013.workers.dev/api/user?id=${user.id}`
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user?id=${user.id}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
const userData = (await userRes.json()) as User
const sharedRes = await fetch(
`https://database.ishaan1013.workers.dev/api/sandbox/share?id=${user.id}`
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox/share?id=${user.id}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
const shared = (await sharedRes.json()) as {
id: string

View File

@ -1,30 +1,36 @@
import { User } from "@/lib/types";
import { currentUser } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { User } from "@/lib/types"
import { currentUser } from "@clerk/nextjs"
import { redirect } from "next/navigation"
export default async function AppAuthLayout({
children,
}: {
children: React.ReactNode;
children: React.ReactNode
}) {
const user = await currentUser();
const user = await currentUser()
if (!user) {
redirect("/");
redirect("/")
}
const dbUser = await fetch(
`https://database.ishaan1013.workers.dev/api/user?id=${user.id}`
);
const dbUserJSON = (await dbUser.json()) as User;
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user?id=${user.id}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
const dbUserJSON = (await dbUser.json()) as User
if (!dbUserJSON.id) {
const res = await fetch(
"https://database.ishaan1013.workers.dev/api/user",
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
body: JSON.stringify({
id: user.id,
@ -32,8 +38,8 @@ export default async function AppAuthLayout({
email: user.emailAddresses[0].emailAddress,
}),
}
);
)
}
return <>{children}</>;
return <>{children}</>
}

View File

@ -18,7 +18,12 @@ export async function POST(request: NextRequest) {
}
const res = await fetch(
`https://database.ishaan1013.workers.dev/api/user?id=${clerkUser.id}`
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user?id=${clerkUser.id}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
const user = (await res.json()) as User

View File

@ -60,9 +60,7 @@ export default function GenerateInput({
regenerate?: boolean
}) => {
if (user.generations >= 10) {
toast.error(
"You reached the maximum # of generations. Contact @ishaandey_ on X/Twitter to reset :)"
)
toast.error("You reached the maximum # of generations.")
return
}

View File

@ -51,8 +51,7 @@ export default function Loading({
</DialogTitle>
{didFail ? (
<DialogDescription className="pt-2">
Try again in a minute, or contact @ishaandey_ on Twitter/X if it
still doesn't work.
Try again soon.
</DialogDescription>
) : description ? (
<DialogDescription className="pt-2">

View File

@ -75,13 +75,17 @@ export default function ShareSandboxModal({
{data.visibility === "private" ? (
<DialogDescription className="text-sm text-muted-foreground">
This sandbox is private. Making it public will allow shared
users to view and collaborate. You can still share & manage access below.
users to view and collaborate. You can still share & manage
access below.
</DialogDescription>
) : null}
</DialogHeader>
<div className="flex space-x-4 w-full">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex w-full">
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex w-full"
>
<FormField
control={form.control}
name="email"
@ -101,7 +105,8 @@ export default function ShareSandboxModal({
<Button disabled={loading} type="submit" className="">
{loading ? (
<>
<Loader2 className="animate-spin mr-2 h-4 w-4" /> Loading...
<Loader2 className="animate-spin mr-2 h-4 w-4" />{" "}
Loading...
</>
) : (
<>
@ -111,11 +116,19 @@ export default function ShareSandboxModal({
</Button>
</form>
</Form>
<Button onClick={() => {
navigator.clipboard.writeText(`https://s.ishaand.com/code/${data.id}`)
toast.success("Link copied to clipboard.")
}} size="icon" disabled={loading} variant="outline" className="shrink-0">
<Link className="h-4 w-4" />
<Button
onClick={() => {
navigator.clipboard.writeText(
`${process.env.NEXT_PUBLIC_APP_URL}/code/${data.id}`
)
toast.success("Link copied to clipboard.")
}}
size="icon"
disabled={loading}
variant="outline"
className="shrink-0"
>
<Link className="h-4 w-4" />
</Button>
</div>
</div>

View File

@ -9,11 +9,12 @@ export async function createSandbox(body: {
visibility: string
}) {
const res = await fetch(
"https://database.ishaan1013.workers.dev/api/sandbox",
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
body: JSON.stringify(body),
}
@ -27,10 +28,11 @@ export async function updateSandbox(body: {
name?: string
visibility?: "public" | "private"
}) {
await fetch("https://database.ishaan1013.workers.dev/api/sandbox", {
await fetch(`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
body: JSON.stringify(body),
})
@ -39,20 +41,27 @@ export async function updateSandbox(body: {
}
export async function deleteSandbox(id: string) {
await fetch(`https://database.ishaan1013.workers.dev/api/sandbox?id=${id}`, {
method: "DELETE",
})
await fetch(
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox?id=${id}`,
{
method: "DELETE",
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
}
)
revalidatePath("/dashboard")
}
export async function shareSandbox(sandboxId: string, email: string) {
const res = await fetch(
"https://database.ishaan1013.workers.dev/api/sandbox/share",
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox/share`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
body: JSON.stringify({ sandboxId, email }),
}
@ -68,13 +77,17 @@ export async function shareSandbox(sandboxId: string, email: string) {
}
export async function unshareSandbox(sandboxId: string, userId: string) {
await fetch("https://database.ishaan1013.workers.dev/api/sandbox/share", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ sandboxId, userId }),
})
await fetch(
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox/share`,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
body: JSON.stringify({ sandboxId, userId }),
}
)
revalidatePath(`/code/${sandboxId}`)
}