wlvz
wlvz
Explore posts from servers
DTDrizzle Team
Created by wlvz on 10/22/2023 in #help
db:push constraint is not found in the table
Hi, I'm using planetscale and trying to push to my db but I get the error: errno: 3821, sql: 'ALTER TABLE Subtopic DROP CONSTRAINT Subtopic_name_key;', sqlState: 'HY000', sqlMessage: target: database.-.primary: vttablet: rpc error: code = Unknown desc = Check constraint 'Subtopic_name_key' is not found in the table. (errno 3821) (sqlstate HY000) (CallerID: yc7blbqh18eaxxd6jg4n): Sql: "alter table Subtopic drop check Subtopic_name_key", BindVars: {REDACTED} Anyone know how I can fix this?
1 replies
TTCTheo's Typesafe Cult
Created by wlvz on 10/22/2023 in #questions
Vercel build: Module not found: Can't resolve '../build/Release/canvas.node'
I've been trying to deploy to vercel but everytime I get the error: build: Module not found: Can't resolve '../build/Release/canvas.node' I've tried redeploying, making changes then pushing to github but nothing works. Before just redeploying would fix it but now it doesn't. Anyone know how I can fix this? It works when building locally but not on Vercel
2 replies
TTCTheo's Typesafe Cult
Created by wlvz on 7/15/2023 in #questions
View but not download with S3
Hi, I have a subscription service that allows users to view certain PDFs that I store on S3, in my NextJS app is there any way to allow the users to still view the PDF but if they try download it they get like a 403 (forbidden) error. I've found a youtube video that kinda does what I'm looking for (https://www.youtube.com/watch?v=x239gnCxGk0&lc=Ugyakc8uGhSM79WxoXd4AaABAg) but it doesn't work for me and I'm not sure how I'd do that with NextJs. Thanks
9 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/29/2023 in #questions
TypeError: Cannot read properties of undefined (reading 'subscribe')
Hi, I have the following code and I keep getting the error "Cannot read properties of undefined (reading 'subscribe'), and I can't figure out how to fix it. This is the code:
export default function Page({ params }: { params: { subject: string } }) {
const router = useRouter();
const pathname = usePathname()
const segments = pathname.split('/');
const subject = segments[2];
const topic = segments[3];

const { data: topics, isLoading: topicsLoading } = useQuery(
['topics'],
async () => {
const response = await fetch('/api/topiclist');
const data = await response.json();
console.log(data); // Log the response data
return data.map((topic: { name: string }) => topic.name.toLowerCase());
}
);

const { data: subjects, isLoading: subjectsLoading } = useQuery(
['subjects'],
async () => {
const response = await fetch('/api/subjectlist');
const data = await response.json();
console.log(data); // Log the response data
return data.map((subject: { name: string }) => subject.name.toLowerCase());
}
);

if (subjects && !subjects.includes(subject)) {
return <p>Exam not found</p>;
}

const capitalizedSubject =
params.subject.charAt(0).toUpperCase() + params.subject.slice(1);

return (
<div>
<h1>{capitalizedSubject} Page</h1>

<h2>Topics for ID: </h2>
<ul>
{topicsLoading ? (
<div>Loading topics...</div>
) : topics && topics.length > 0 ? (
topics.map((topic: string, index: number) => (
<CommandItem key={index}>
<Calendar className="mr-2 h-4 w-4" />
<Link href={`/exams/${topic}`}>{topic}</Link>
</CommandItem>
))
) : (
<div>No topics available.</div>
)}
</ul>
</div>
);
}
export default function Page({ params }: { params: { subject: string } }) {
const router = useRouter();
const pathname = usePathname()
const segments = pathname.split('/');
const subject = segments[2];
const topic = segments[3];

const { data: topics, isLoading: topicsLoading } = useQuery(
['topics'],
async () => {
const response = await fetch('/api/topiclist');
const data = await response.json();
console.log(data); // Log the response data
return data.map((topic: { name: string }) => topic.name.toLowerCase());
}
);

const { data: subjects, isLoading: subjectsLoading } = useQuery(
['subjects'],
async () => {
const response = await fetch('/api/subjectlist');
const data = await response.json();
console.log(data); // Log the response data
return data.map((subject: { name: string }) => subject.name.toLowerCase());
}
);

if (subjects && !subjects.includes(subject)) {
return <p>Exam not found</p>;
}

const capitalizedSubject =
params.subject.charAt(0).toUpperCase() + params.subject.slice(1);

return (
<div>
<h1>{capitalizedSubject} Page</h1>

<h2>Topics for ID: </h2>
<ul>
{topicsLoading ? (
<div>Loading topics...</div>
) : topics && topics.length > 0 ? (
topics.map((topic: string, index: number) => (
<CommandItem key={index}>
<Calendar className="mr-2 h-4 w-4" />
<Link href={`/exams/${topic}`}>{topic}</Link>
</CommandItem>
))
) : (
<div>No topics available.</div>
)}
</ul>
</div>
);
}
When I hard refresh the page, it loads for a second and renders but then immediately after the error comes.
5 replies
DTDrizzle Team
Created by wlvz on 6/28/2023 in #help
Cannot read properties of undefined (reading 'connectionString')
In my drizzle.config.ts I have the code:
import type { Config } from "drizzle-kit";
import 'dotenv/config'

export default {
schema: "./lib/db/schema.ts",
out: "./drizzle",
connectionString: process.env.DATABASE_URL,
driver: "mysql2",
} satisfies Config;
import type { Config } from "drizzle-kit";
import 'dotenv/config'

export default {
schema: "./lib/db/schema.ts",
out: "./drizzle",
connectionString: process.env.DATABASE_URL,
driver: "mysql2",
} satisfies Config;
and when I go to run drizzle-kit introspect:mysql I get the error:
TypeError: Cannot read properties of undefined (reading 'connectionString').
TypeError: Cannot read properties of undefined (reading 'connectionString').
I checked my .env.local and DATABASE_URL is defined:
DATABASE_URL='mysql://abcd@aws.connect.psdb.cloud/username?ssl={"rejectUnauthorized":true}'
DATABASE_URL='mysql://abcd@aws.connect.psdb.cloud/username?ssl={"rejectUnauthorized":true}'
3 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/27/2023 in #questions
Invalid input Only "mysql2" is available options for "--driver"
I'm trying to run drizzle-kit introspect:mysql by following the docs and I have the config file:
import type { Config } from "drizzle-kit";
import dotenv from "dotenv";
dotenv.config({ path: " .env.local" });

export default {
schema: "./lib/db/schema.ts",
out: "./drizzle",
connectionString: process.env.DATABASE_URL,
} satisfies Config;
import type { Config } from "drizzle-kit";
import dotenv from "dotenv";
dotenv.config({ path: " .env.local" });

export default {
schema: "./lib/db/schema.ts",
out: "./drizzle",
connectionString: process.env.DATABASE_URL,
} satisfies Config;
and in my package.json I have:
"introspect": "drizzle-kit introspect:mysql"
"introspect": "drizzle-kit introspect:mysql"
in my scripts. But when I go to run "npm run introspect" I get the error:
drizzle-kit: v0.19.2
drizzle-orm: v0.27.0

No config path provided, using default 'drizzle.config.ts'
Reading config file '/Users/user/Code/testproject/drizzle.config.ts'
Invalid input Only "mysql2" is available options for "--driver"
drizzle-kit: v0.19.2
drizzle-orm: v0.27.0

No config path provided, using default 'drizzle.config.ts'
Reading config file '/Users/user/Code/testproject/drizzle.config.ts'
Invalid input Only "mysql2" is available options for "--driver"
3 replies
DTDrizzle Team
Created by wlvz on 6/27/2023 in #help
Invalid input Only "mysql2" is available options for "--driver"
I'm trying to run drizzle-kit introspect:mysql by following the docs and I have the config file:
import type { Config } from "drizzle-kit";
import dotenv from "dotenv";
dotenv.config({ path: " .env.local" });

export default {
schema: "./lib/db/schema.ts",
out: "./drizzle",
connectionString: process.env.DATABASE_URL,
} satisfies Config;
import type { Config } from "drizzle-kit";
import dotenv from "dotenv";
dotenv.config({ path: " .env.local" });

export default {
schema: "./lib/db/schema.ts",
out: "./drizzle",
connectionString: process.env.DATABASE_URL,
} satisfies Config;
and in my package.json I have:
"introspect": "drizzle-kit introspect:mysql"
"introspect": "drizzle-kit introspect:mysql"
in my scripts. But when I go to run "npm run introspect" I get the error:
drizzle-kit: v0.19.2
drizzle-orm: v0.27.0

No config path provided, using default 'drizzle.config.ts'
Reading config file '/Users/user/Code/testproject/drizzle.config.ts'
Invalid input Only "mysql2" is available options for "--driver"
drizzle-kit: v0.19.2
drizzle-orm: v0.27.0

No config path provided, using default 'drizzle.config.ts'
Reading config file '/Users/user/Code/testproject/drizzle.config.ts'
Invalid input Only "mysql2" is available options for "--driver"
4 replies
DTDrizzle Team
Created by wlvz on 6/25/2023 in #help
net::ERR_NAME_NOT_RESOLVED
Hi, I was following the drizzle planetscale starter made by josh (https://github.com/joschan21/drizzle-planetscale-starter) and I came across some erros I didn't know how to fix. I have the following server component:
import { db } from "app/lib/db/index";
import { subjects } from "app/lib/db/schema"

export const runtime = 'edge'

export default async function Home() {
const subjectList = await db.select().from(subjects)

return (
<>
<p>my subjects:</p>
{subjectList.map((subject) => (
<div key={subject.id}>{subject.name}</div>
))}
</>
)
}
import { db } from "app/lib/db/index";
import { subjects } from "app/lib/db/schema"

export const runtime = 'edge'

export default async function Home() {
const subjectList = await db.select().from(subjects)

return (
<>
<p>my subjects:</p>
{subjectList.map((subject) => (
<div key={subject.id}>{subject.name}</div>
))}
</>
)
}
and when I try view this I get thousands of console errors (more errors just keep coming, its like an infinite amount of console errors) of just the same thing:
// index.js:115 POST https://undefined/psdb.v1alpha1.Database/Execute net::ERR_NAME_NOT_RESOLVED
// index.js:115 POST https://undefined/psdb.v1alpha1.Database/Execute net::ERR_NAME_NOT_RESOLVED
I'm pretty sure this has to do with my database URL, but I could be wrong My db/index looks like this:
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { connect } from "@planetscale/database";

// create the connection
const connection = connect({
host: process.env.DATABASE_URL,
});

export const db = drizzle(connection);
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { connect } from "@planetscale/database";

// create the connection
const connection = connect({
host: process.env.DATABASE_URL,
});

export const db = drizzle(connection);
and my drizzle.config.ts looks like this:
import type { Config } from "drizzle-kit";

export default {
schema: "./app/lib/db/schema.ts",
out: "./drizzle",
dbCredentials: {
connectionString: process.env.DATABASE_URL,
}
} satisfies Config;
import type { Config } from "drizzle-kit";

export default {
schema: "./app/lib/db/schema.ts",
out: "./drizzle",
dbCredentials: {
connectionString: process.env.DATABASE_URL,
}
} satisfies Config;
my .env looks like this:
DATABASE_URL='mysql:url@aws.connect.psdb.cloud/mydbname?ssl={"rejectUnauthorized":true}'
DATABASE_URL='mysql:url@aws.connect.psdb.cloud/mydbname?ssl={"rejectUnauthorized":true}'
with ?ssl={"rejectUnauthorized":true} coming from the docs. any idea on how to fix this? thanks
3 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/24/2023 in #questions
net::ERR_NAME_NOT_RESOLVED Drizzle ORM
Hi, I have the following server component:
import { db } from "app/lib/db/index";
import { subjects } from "app/lib/db/schema"

export const runtime = 'edge'

export default async function Home() {
const users = await db.select().from(subjects)

return (
<>
<p>my users:</p>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</>
)
}
import { db } from "app/lib/db/index";
import { subjects } from "app/lib/db/schema"

export const runtime = 'edge'

export default async function Home() {
const users = await db.select().from(subjects)

return (
<>
<p>my users:</p>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</>
)
}
and when I try view this I get thousands of console errors of just the same thing:
// index.js:115 POST https://undefined/psdb.v1alpha1.Database/Execute net::ERR_NAME_NOT_RESOLVED
// index.js:115 POST https://undefined/psdb.v1alpha1.Database/Execute net::ERR_NAME_NOT_RESOLVED
I'm pretty sure this has to do with my database URL My db/index looks like this:
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { connect } from "@planetscale/database";

// create the connection
const connection = connect({
host: process.env.DATABASE_URL,
});

export const db = drizzle(connection);
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { connect } from "@planetscale/database";

// create the connection
const connection = connect({
host: process.env.DATABASE_URL,
});

export const db = drizzle(connection);
and my drizzle.config.ts looks like this:
import type { Config } from "drizzle-kit";

export default {
schema: "./app/lib/db/schema.ts",
out: "./drizzle",
dbCredentials: {
connectionString: process.env.DATABASE_URL,
}
} satisfies Config;
import type { Config } from "drizzle-kit";

export default {
schema: "./app/lib/db/schema.ts",
out: "./drizzle",
dbCredentials: {
connectionString: process.env.DATABASE_URL,
}
} satisfies Config;
my .env looks like this:
DATABASE_URL='mysql:url@aws.connect.psdb.cloud/mydbname?ssl={"rejectUnauthorized":true}'
DATABASE_URL='mysql:url@aws.connect.psdb.cloud/mydbname?ssl={"rejectUnauthorized":true}'
with ?ssl={"rejectUnauthorized":true} coming from the docs. any idea on how to fix this?
2 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/22/2023 in #questions
Prisma Data Proxy vs Drizzle
Has anyone tried Prisma's data proxy? I'm currently just using Prisma regularly and it takes ~ 3 - 5 seconds to fetch a simple array from my DB and it's extremely inconsistent with response times varying, I use nextJS to write my API call
export async function GET(request: Request) {
try {
const url = new URL(request.url);
const topicId = parseInt(url.searchParams.get("topicId") ?? "", 10);
console.log("Received topicId:", topicId);

const topic = await db.topic.findUnique({
where: {
id: topicId,
},
include: {
subtopics: {
select: {
name: true,
},
},
},
});

if (!topic) {
return new Response(null, { status: 404 });
}

const subtopicNames = topic.subtopics.map((subtopic) => subtopic.name);

return new Response(JSON.stringify(subtopicNames));
} catch (error) {
return new Response(null, { status: 500 });
}
}
export async function GET(request: Request) {
try {
const url = new URL(request.url);
const topicId = parseInt(url.searchParams.get("topicId") ?? "", 10);
console.log("Received topicId:", topicId);

const topic = await db.topic.findUnique({
where: {
id: topicId,
},
include: {
subtopics: {
select: {
name: true,
},
},
},
});

if (!topic) {
return new Response(null, { status: 404 });
}

const subtopicNames = topic.subtopics.map((subtopic) => subtopic.name);

return new Response(JSON.stringify(subtopicNames));
} catch (error) {
return new Response(null, { status: 500 });
}
}
Client Side: This call takes around 3-5 seconds from making the request to rendering it on the client side (I use react query on the client side). I was wondering if I use Prisma's data proxy would this be noticably faster? I'm aiming for around < 1s to 1s but as long as it's faster idm. Prisma's data proxy allows you to use the edge with Prisma which I'd rather do instead of switching to Drizzle however if Prisma's data proxy is still significantly slower than Drizzle I'd rather make the switch. The biggest issue rn is cold starts which is why I want to use the edge, in their docs Prisma advertises "Faster cold starts" but I'm not sure how much faster it'll be. I console logged the time the response would take and the first (cold start) req takes: 2640.547416985035 milliseconds (2.6s) and after that it takes 487.4787500202656 milliseconds (0.487s). Is it worth using Prisma's data proxy or should I just switch to Drizzle? Thanks
8 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/21/2023 in #questions
CORS Issue on only some API calls
I have multiple API calls on my project deployed to vercel but only some of them face CORS issues, for example:
import { db } from "../../lib/db";

export async function GET() {
const start = performance.now();

try {
const posts = await db.subjects.findMany({
select: {
id: true,
name: true,
},
});
const end = performance.now();
console.log(`API call took ${end - start} milliseconds`);
return new Response(JSON.stringify(posts));
} catch (error) {
return new Response(null, { status: 500 });
}
}
import { db } from "../../lib/db";

export async function GET() {
const start = performance.now();

try {
const posts = await db.subjects.findMany({
select: {
id: true,
name: true,
},
});
const end = performance.now();
console.log(`API call took ${end - start} milliseconds`);
return new Response(JSON.stringify(posts));
} catch (error) {
return new Response(null, { status: 500 });
}
}
works perfectly fine however
import { db } from "../../lib/db";

const headers = {
"Access-Control-Allow-Origin": "https://examvault.vercel.app",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
};

export async function GET(request: Request) {
try {
const url = new URL(request.url);
const name = url.searchParams.get("name") || "";
console.log("Received subject name:", name);

const subjects = await db.topic.findMany({
where: {
name: {
equals: name,
},
},
select: {
id: true,
},
});

if (subjects.length === 0) {
return new Response(null, { status: 404 });
}

const { id } = subjects[0];

const headers = {
"Access-Control-Allow-Origin":
"https://examvault-danielarbabian.vercel.app",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "Content-Type",
};

return new Response(JSON.stringify(id));
} catch (error) {
return new Response(null, { status: 500 });
}
}
import { db } from "../../lib/db";

const headers = {
"Access-Control-Allow-Origin": "https://examvault.vercel.app",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
};

export async function GET(request: Request) {
try {
const url = new URL(request.url);
const name = url.searchParams.get("name") || "";
console.log("Received subject name:", name);

const subjects = await db.topic.findMany({
where: {
name: {
equals: name,
},
},
select: {
id: true,
},
});

if (subjects.length === 0) {
return new Response(null, { status: 404 });
}

const { id } = subjects[0];

const headers = {
"Access-Control-Allow-Origin":
"https://examvault-danielarbabian.vercel.app",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "Content-Type",
};

return new Response(JSON.stringify(id));
} catch (error) {
return new Response(null, { status: 500 });
}
}
doesn't work when visiting the production URL despite the first one working. I get this error: Access to XMLHttpRequest at 'http://localhost:3000/api/fetchtopicid?name=electricity' from origin '' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
15 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/17/2023 in #questions
Error: PrismaClient is unable to be run in the browser.
12 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/10/2023 in #questions
ESLint changes don't show when running turbo build
Hi, in my .eslintrc.cjs file I've made some changes which include warning instead of throwing errors for certain rules, for example this is my file:
rules: {
"@typescript-eslint/consistent-type-imports": [
"warn",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-misused-promises": "warn",
"@typescript-eslint/restrict-template-expressions": "warn",
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
},
rules: {
"@typescript-eslint/consistent-type-imports": [
"warn",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-misused-promises": "warn",
"@typescript-eslint/restrict-template-expressions": "warn",
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
},
I've changed "no-misused-promises" to warn instead of showing an error but when I run turbo build I get the error:
build: 126:22 Error: Promise-returning function provided to attribute where a void return was expected. @typescript-eslint/no-misused-promises
build: 126:22 Error: Promise-returning function provided to attribute where a void return was expected. @typescript-eslint/no-misused-promises
Shouldn't this just show a warning instead of throwing an error or am I doing something wrong? I'm using Next 13.4 with the app router and this occurs when running both npm run build and turbo build. When I change them from warn to off the error still occurs.
8 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/7/2023 in #questions
prisma nested writes / updates not working
My prisma schema currently looks like this:
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}

model Exams {
id Int @default(autoincrement()) @id
name String
file String
subject String?
year Int
}

model Subjects {
id Int @default(autoincrement()) @id
name String
topics Topic[]
}

model Topic {
id Int @default(autoincrement()) @id
name String
subjectId Int
subject Subjects @relation(fields: [subjectId], references: [id])
@@index([subjectId])
}
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}

model Exams {
id Int @default(autoincrement()) @id
name String
file String
subject String?
year Int
}

model Subjects {
id Int @default(autoincrement()) @id
name String
topics Topic[]
}

model Topic {
id Int @default(autoincrement()) @id
name String
subjectId Int
subject Subjects @relation(fields: [subjectId], references: [id])
@@index([subjectId])
}
I want to make an API call which creates a topic specific to a subject. For example, if I specify that the subject is biology, it should make a new topic nested under biology. This is my current code which attempts that:
import { db } from "../../lib/db"
import type { NextApiRequest, NextApiResponse } from 'next';
import { SubjectsWhereUniqueInput } from './types';

export async function POST(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const { name, subject } = req.body;
const subjectRecord = await db.subjects.findUnique({
where: { name: subject } as SubjectsWhereUniqueInput,
});

if (!subjectRecord) {
return res.status(404).json({ message: 'Subject not found' });
}

const topic = await db.topic.create({
data: {
name,
subject: { connect: { id: subjectRecord.id } },
},
});
res.status(201).json(topic);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
}
import { db } from "../../lib/db"
import type { NextApiRequest, NextApiResponse } from 'next';
import { SubjectsWhereUniqueInput } from './types';

export async function POST(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const { name, subject } = req.body;
const subjectRecord = await db.subjects.findUnique({
where: { name: subject } as SubjectsWhereUniqueInput,
});

if (!subjectRecord) {
return res.status(404).json({ message: 'Subject not found' });
}

const topic = await db.topic.create({
data: {
name,
subject: { connect: { id: subjectRecord.id } },
},
});
res.status(201).json(topic);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
}
However when I try calling this API I get a 405 error, in addition to that I'm pretty sure the way I'm trying to do this is wrong as well. How would I be able to do this? Thanks
8 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/5/2023 in #questions
Dynamic Routes with AWS Object Keys
Hi, I'm currently building a website where I need to fetch PDF's from S3. I've managed to get that working however the object key is currently hardcoded. I want to change this so that my object key gets taken from the URL. For example, if the user visits /exams/biology/photosynthesis1 it sets the object key to biology/photosynthesis1. If they visit /exams/physics/forces, it sets the object key to physics/forces. How would I do that? I've attached my code below:
23 replies
TTCTheo's Typesafe Cult
Created by wlvz on 6/3/2023 in #questions
405 Error with S3 Presigned URL's
I currently have a 'PDF viewer' on my website which is suppose to render a PDF from my s3 bucket and prevent the user from being able to download, print, etc the pdf. Here's the code for the /exams/page.tsx file (the PDF viewer)
"use client";
import React, { useState, useEffect } from "react";

const PDFViewer = (presignedUrl: RequestInfo | URL) => {
const [pdfUrl, setPdfUrl] = useState("");

useEffect(() => {
const fetchPdf = async () => {
try {
const objectKey = "biology/Photosynthesis 1.pdf";
const response = await fetch(`/api/exams?objectKey=${objectKey}`);
const pdfObjectUrl = URL.createObjectURL(await response.blob());
setPdfUrl(pdfObjectUrl);
} catch (error) {
console.error("Error fetching PDF:", error);
}
};

fetchPdf();

return () => {
if (pdfUrl) {
URL.revokeObjectURL(pdfUrl);
}
};
}, []);

const handleContextMenu = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
event.preventDefault();
};

const handleMouseDown = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
if (event.button === 2) {
event.preventDefault();
}
};

return (
<div
className="fixed inset-0 flex items-center justify-center"
onContextMenu={handleContextMenu}
onMouseDown={handleMouseDown}
>
<div className="absolute inset-0 bg-gray-900 opacity-75 pointer-events-none" />
<div className="relative w-full h-full flex items-center justify-center">
{pdfUrl ? (
<embed
src={`${pdfUrl}#toolbar=0`}
type="application/pdf"
className="w-full h-full"
onContextMenu={handleContextMenu}
/>
) : (
<p>Loading PDF...</p>
)}
</div>
</div>
);
};

export default PDFViewer;
"use client";
import React, { useState, useEffect } from "react";

const PDFViewer = (presignedUrl: RequestInfo | URL) => {
const [pdfUrl, setPdfUrl] = useState("");

useEffect(() => {
const fetchPdf = async () => {
try {
const objectKey = "biology/Photosynthesis 1.pdf";
const response = await fetch(`/api/exams?objectKey=${objectKey}`);
const pdfObjectUrl = URL.createObjectURL(await response.blob());
setPdfUrl(pdfObjectUrl);
} catch (error) {
console.error("Error fetching PDF:", error);
}
};

fetchPdf();

return () => {
if (pdfUrl) {
URL.revokeObjectURL(pdfUrl);
}
};
}, []);

const handleContextMenu = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
event.preventDefault();
};

const handleMouseDown = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
if (event.button === 2) {
event.preventDefault();
}
};

return (
<div
className="fixed inset-0 flex items-center justify-center"
onContextMenu={handleContextMenu}
onMouseDown={handleMouseDown}
>
<div className="absolute inset-0 bg-gray-900 opacity-75 pointer-events-none" />
<div className="relative w-full h-full flex items-center justify-center">
{pdfUrl ? (
<embed
src={`${pdfUrl}#toolbar=0`}
type="application/pdf"
className="w-full h-full"
onContextMenu={handleContextMenu}
/>
) : (
<p>Loading PDF...</p>
)}
</div>
</div>
);
};

export default PDFViewer;
(continued because im running out of characters)
12 replies
TTCTheo's Typesafe Cult
Created by wlvz on 5/26/2023 in #questions
get S3 Object (pdf) and display it on a unique url based on object name
Hi, I currently have multiple pdfs held on S3 and I'm building an app where I need to display these PDFs based on the name of the object. For example, I have a pdf named photosynthesis 1.pdf, it's held in the biology/ folder and I need to display this pdf on domain.com/exams/{biology}/{photosynthesis 1.pdf} How can I make it so that when a user visits this url, it displays the pdf related to that url on the site. Or should I approach this differently? I've tried searching but couldn't find anything that worked, I'm pretty new to S3 so I'm a little lost. Another option I'm considering is waiting on upload thing to support pdfs and using that instead but I'm not sure when that will be ready and I need to finish the site ASAP. Thanks
4 replies