Trader Launchpad
Trader Launchpad
Explore posts from servers
DTDrizzle Team
Created by Trader Launchpad on 4/29/2024 in #help
How to structure posts with categories using drizzle and postgres (supabase)
Ah that works most of the way. I think i can figure it out from here! THANK YOU
8 replies
DTDrizzle Team
Created by Trader Launchpad on 4/29/2024 in #help
How to structure posts with categories using drizzle and postgres (supabase)
@Sillvva I get error: TRPCClientError: invalid reference to FROM-clause entry for table "create-t3-app_businessEntity
8 replies
DTDrizzle Team
Created by Trader Launchpad on 4/29/2024 in #help
How to structure posts with categories using drizzle and postgres (supabase)
I will test and let you know asap
8 replies
DTDrizzle Team
Created by Trader Launchpad on 4/29/2024 in #help
How to structure posts with categories using drizzle and postgres (supabase)
My Trpc query:
getAll: publicProcedure
.input(
z.object({
limit: z.number().min(1).max(100).default(20).optional(),
cursor: z.number().nullish(), // <-- "cursor" needs to exist, but can be any type
direction: z
.enum(["forward", "backward"])
.default("forward")
.optional(), // optional, useful for bi-directional query
categoryId: z.number().optional(),
categories: z.array(z.number()).optional(),
}),
)
.query(async ({ ctx, input }) => {
const limit = input.limit ?? 50;
const items = await ctx.db.query.businessEntitys.findMany({

where: input.cursor ? gt(businessEntitys.id, input.cursor) : undefined,
with: {
reviews: true,
businessEntityCategories: {
with: {
categories: true,
},
},
},
limit: limit,
orderBy: asc(businessEntitys.id),
});

let nextCursor: typeof input.cursor | undefined = undefined;
if (items.length > limit) {
const nextItem = items.pop();
nextCursor = nextItem!.id;
}
return {
items,
nextCursor,
};
}),
getAll: publicProcedure
.input(
z.object({
limit: z.number().min(1).max(100).default(20).optional(),
cursor: z.number().nullish(), // <-- "cursor" needs to exist, but can be any type
direction: z
.enum(["forward", "backward"])
.default("forward")
.optional(), // optional, useful for bi-directional query
categoryId: z.number().optional(),
categories: z.array(z.number()).optional(),
}),
)
.query(async ({ ctx, input }) => {
const limit = input.limit ?? 50;
const items = await ctx.db.query.businessEntitys.findMany({

where: input.cursor ? gt(businessEntitys.id, input.cursor) : undefined,
with: {
reviews: true,
businessEntityCategories: {
with: {
categories: true,
},
},
},
limit: limit,
orderBy: asc(businessEntitys.id),
});

let nextCursor: typeof input.cursor | undefined = undefined;
if (items.length > limit) {
const nextItem = items.pop();
nextCursor = nextItem!.id;
}
return {
items,
nextCursor,
};
}),
8 replies
DTDrizzle Team
Created by Trader Launchpad on 4/29/2024 in #help
How to structure posts with categories using drizzle and postgres (supabase)
export const businessEntityCategories = createTable(
"businessEntityCategories",
{
businessEntityId: integer("businessEntityId").references(
() => businessEntitys.id,
{ onDelete: "cascade" },
),
categoryId: integer("categoryId").references(() => categories.id, {
onDelete: "cascade",
}),
},
(table) => {
return {
pk: primaryKey({ columns: [table.businessEntityId, table.categoryId] }),
};
},
);

export const businessEntityCategoriesRelations = relations(
businessEntityCategories,
({ one }) => ({
business: one(businessEntitys, {
fields: [businessEntityCategories.businessEntityId],
references: [businessEntitys.id],
}),
categories: one(categories, {
fields: [businessEntityCategories.categoryId],
references: [categories.id],
}),
}),
);
export const businessEntityCategories = createTable(
"businessEntityCategories",
{
businessEntityId: integer("businessEntityId").references(
() => businessEntitys.id,
{ onDelete: "cascade" },
),
categoryId: integer("categoryId").references(() => categories.id, {
onDelete: "cascade",
}),
},
(table) => {
return {
pk: primaryKey({ columns: [table.businessEntityId, table.categoryId] }),
};
},
);

export const businessEntityCategoriesRelations = relations(
businessEntityCategories,
({ one }) => ({
business: one(businessEntitys, {
fields: [businessEntityCategories.businessEntityId],
references: [businessEntitys.id],
}),
categories: one(categories, {
fields: [businessEntityCategories.categoryId],
references: [categories.id],
}),
}),
);
8 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 2/16/2024 in #questions
CTA v7.26.0 is giving "fetch is not a function" error
@cje Found the answer. I had to modify next.config:
await import("./src/env.mjs");

/** @type {import("next").NextConfig} */
const config = {
experimental: {
serverComponentsExternalPackages: ["monday-sdk-js"],
},
};

export default config;
await import("./src/env.mjs");

/** @type {import("next").NextConfig} */
const config = {
experimental: {
serverComponentsExternalPackages: ["monday-sdk-js"],
},
};

export default config;
7 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 2/16/2024 in #questions
CTA v7.26.0 is giving "fetch is not a function" error
it does. Also spinning up a ct3app and downgrading the next version to 13.4 fixes the issue. It is something to do with next between 13.4 and 14.x. I believe has something to do with no longer needing the serverAction experimental flag, or the fact that nextjs14 no longer polyfills node-fetch. i have searched for a few days, on nextjs and monday-sdk-js githubs, opened a few issues and discussions. No one has responded.
7 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 2/16/2024 in #questions
CTA v7.26.0 is giving "fetch is not a function" error
I am still struggling with this.
7 replies
TtRPC
Created by Trader Launchpad on 2/14/2024 in #❓-help
Thoughts on how to integrate t3 app, connectkit web3 auth, nextjs middleware, and trpc
The matcher is stock from nextjs documentation, and it runs on every route including /api and trpc calls. When I have this middleware enabled I am getting an error on the front page of t3 app, on the standard post.hello trpc call:
RequestContentLengthMismatchError: Request body length does not match content-length header
RequestContentLengthMismatchError: Request body length does not match content-length header
When I disable the middleware, this issue goes away. I believe it is due to my nextjs middleware matcher running on every request, and blocking /siwe as a publicpath if they ARE authenticated, sending them to / and something is getitng lost on the trpc side. To clarify on a page reload the middleware is hit multiple times, once on "/", once on "/siwe" which is triggered every page reload by the ClientProvider. The error only happens on the call that originated from "/siwe" Strangely if I simply move /siwe to /api/siwe, the error goes away. Also if I remove the
if (isPublicPath) {
if (isPublicPath) {
logic the error goes away. What is the correct way to setup the nextjs middleware in this situation? Should I just add /siwe as an ignored route in the middleware matcher? Should i be putting my /siwe logic in trpc routes and calling it that way (api.user.getNonce, api.user.verifyNonce. api.user.createSession, ect)?
4 replies
TtRPC
Created by Trader Launchpad on 2/14/2024 in #❓-help
Thoughts on how to integrate t3 app, connectkit web3 auth, nextjs middleware, and trpc
const siweConfig = {
getNonce: async () => {
const res = await fetch(`/siwe`, { method: "PUT" });
if (!res.ok) throw new Error("Failed to fetch SIWE nonce");

return res.text();
},
createMessage: ({ nonce, address, chainId }) => {
return new SiweMessage({
nonce,
chainId,
address,
version: "1",
uri: window.location.origin,
domain: window.location.host,
statement: "Sign In With Ethereum to prove you control this wallet.",
}).prepareMessage();
},
verifyMessage: ({ message, signature }) => {
return fetch(`/siwe`, {
method: "POST",
body: JSON.stringify({ message, signature }),
headers: { "Content-Type": "application/json" },
}).then((res) => res.ok);
},
getSession: async () => {
const res = await fetch(`/siwe`);
if (!res.ok) throw new Error("Failed to fetch SIWE session");

const { address, chainId } = await res.json();
return address && chainId ? { address, chainId } : null;
},
signOut: () => fetch(`/siwe`, { method: "DELETE" }).then((res) => res.ok),
} satisfies SIWEConfig;
const siweConfig = {
getNonce: async () => {
const res = await fetch(`/siwe`, { method: "PUT" });
if (!res.ok) throw new Error("Failed to fetch SIWE nonce");

return res.text();
},
createMessage: ({ nonce, address, chainId }) => {
return new SiweMessage({
nonce,
chainId,
address,
version: "1",
uri: window.location.origin,
domain: window.location.host,
statement: "Sign In With Ethereum to prove you control this wallet.",
}).prepareMessage();
},
verifyMessage: ({ message, signature }) => {
return fetch(`/siwe`, {
method: "POST",
body: JSON.stringify({ message, signature }),
headers: { "Content-Type": "application/json" },
}).then((res) => res.ok);
},
getSession: async () => {
const res = await fetch(`/siwe`);
if (!res.ok) throw new Error("Failed to fetch SIWE session");

const { address, chainId } = await res.json();
return address && chainId ? { address, chainId } : null;
},
signOut: () => fetch(`/siwe`, { method: "DELETE" }).then((res) => res.ok),
} satisfies SIWEConfig;
Then i have setup a custom nextjs middleware that checks the cookie, and redirects based on authenticated or unauthenticated status:
const PUBLIC_PATHS = ["/register", "/login", "/reset-password", "/siwe"];
...
const session = await Session.fromRequest(request);
if (session.address) {
// User is authenticated
console.log("Authenticated");
if (isPublicPath) {
// Redirect authenticated users away from public paths to the home page
url.pathname = "/";
return NextResponse.redirect(url);
}
...
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
const PUBLIC_PATHS = ["/register", "/login", "/reset-password", "/siwe"];
...
const session = await Session.fromRequest(request);
if (session.address) {
// User is authenticated
console.log("Authenticated");
if (isPublicPath) {
// Redirect authenticated users away from public paths to the home page
url.pathname = "/";
return NextResponse.redirect(url);
}
...
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
4 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 2/14/2024 in #questions
Thoughts on how to integrate t3 app, connectkit web3 auth, nextjs middleware, and trpc
The matcher is stock from nextjs documentation, and it runs on every route including /api and trpc calls. When I have this middleware enabled I am getting an error on the front page of t3 app, on the standard post.hello trpc call:
RequestContentLengthMismatchError: Request body length does not match content-length header
RequestContentLengthMismatchError: Request body length does not match content-length header
When I disable the middleware, this issue goes away. I believe it is due to my nextjs middleware matcher running on every request, and blocking /siwe as a publicpath if they ARE authenticated, sending them to / and something is getitng lost on the trpc side. To clarify on a page reload the middleware is hit multiple times, once on "/", once on "/siwe" which is triggered every page reload by the ClientProvider. The error only happens on the call that originated from "/siwe" Strangely if I simply move /siwe to /api/siwe, the error goes away. Also if I remove the
if (isPublicPath) {
if (isPublicPath) {
logic the error goes away. What is the correct way to setup the nextjs middleware in this situation? Should I just add /siwe as an ignored route in the middleware matcher? Should i be putting my /siwe logic in trpc routes and calling it that way (api.user.getNonce, api.user.verifyNonce. api.user.createSession, ect)?
4 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 2/14/2024 in #questions
Thoughts on how to integrate t3 app, connectkit web3 auth, nextjs middleware, and trpc
const siweConfig = {
getNonce: async () => {
const res = await fetch(`/siwe`, { method: "PUT" });
if (!res.ok) throw new Error("Failed to fetch SIWE nonce");

return res.text();
},
createMessage: ({ nonce, address, chainId }) => {
return new SiweMessage({
nonce,
chainId,
address,
version: "1",
uri: window.location.origin,
domain: window.location.host,
statement: "Sign In With Ethereum to prove you control this wallet.",
}).prepareMessage();
},
verifyMessage: ({ message, signature }) => {
return fetch(`/siwe`, {
method: "POST",
body: JSON.stringify({ message, signature }),
headers: { "Content-Type": "application/json" },
}).then((res) => res.ok);
},
getSession: async () => {
const res = await fetch(`/siwe`);
if (!res.ok) throw new Error("Failed to fetch SIWE session");

const { address, chainId } = await res.json();
return address && chainId ? { address, chainId } : null;
},
signOut: () => fetch(`/siwe`, { method: "DELETE" }).then((res) => res.ok),
} satisfies SIWEConfig;
const siweConfig = {
getNonce: async () => {
const res = await fetch(`/siwe`, { method: "PUT" });
if (!res.ok) throw new Error("Failed to fetch SIWE nonce");

return res.text();
},
createMessage: ({ nonce, address, chainId }) => {
return new SiweMessage({
nonce,
chainId,
address,
version: "1",
uri: window.location.origin,
domain: window.location.host,
statement: "Sign In With Ethereum to prove you control this wallet.",
}).prepareMessage();
},
verifyMessage: ({ message, signature }) => {
return fetch(`/siwe`, {
method: "POST",
body: JSON.stringify({ message, signature }),
headers: { "Content-Type": "application/json" },
}).then((res) => res.ok);
},
getSession: async () => {
const res = await fetch(`/siwe`);
if (!res.ok) throw new Error("Failed to fetch SIWE session");

const { address, chainId } = await res.json();
return address && chainId ? { address, chainId } : null;
},
signOut: () => fetch(`/siwe`, { method: "DELETE" }).then((res) => res.ok),
} satisfies SIWEConfig;
Then i have setup a custom nextjs middleware that checks the cookie, and redirects based on authenticated or unauthenticated status:
const PUBLIC_PATHS = ["/register", "/login", "/reset-password", "/siwe"];
...
const session = await Session.fromRequest(request);
if (session.address) {
// User is authenticated
console.log("Authenticated");
if (isPublicPath) {
// Redirect authenticated users away from public paths to the home page
url.pathname = "/";
return NextResponse.redirect(url);
}
...
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
const PUBLIC_PATHS = ["/register", "/login", "/reset-password", "/siwe"];
...
const session = await Session.fromRequest(request);
if (session.address) {
// User is authenticated
console.log("Authenticated");
if (isPublicPath) {
// Redirect authenticated users away from public paths to the home page
url.pathname = "/";
return NextResponse.redirect(url);
}
...
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
4 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 1/29/2024 in #questions
Difference between NextAuth + firebase adapter, NextAuth + drizzle adapter, and just using firebase?
No description
6 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 1/29/2024 in #questions
Difference between NextAuth + firebase adapter, NextAuth + drizzle adapter, and just using firebase?
@Matheus Lasserre Lets say I use Nextauth + drizzle adapter (planetscale) and during the nextauth callback I generate a Firebase custom token and save it into the nextauth session:

...
session: async ({ session, token }) => {
if (session?.user) {
if (token.sub) {
session.user.id = token.sub;

const firebaseToken = await adminAuth.createCustomToken(token.sub);
session.firebaseToken = firebaseToken;
}
}
return session;
},
...

...
session: async ({ session, token }) => {
if (session?.user) {
if (token.sub) {
session.user.id = token.sub;

const firebaseToken = await adminAuth.createCustomToken(token.sub);
session.firebaseToken = firebaseToken;
}
}
return session;
},
...
and then wrap my app in a FirebaseAuthProvider that logs the user in with Firebase:
...
useEffect(() => {
if (session?.firebaseToken) {
signInWithCustomToken(auth, session.firebaseToken)
.then(() => {
console.log(
"Successfully signed in with Firebase using custom token.",
);
})
.catch((error) => {
console.error("Error signing in with custom token:", error);
});
}
}, [session]);
...
...
useEffect(() => {
if (session?.firebaseToken) {
signInWithCustomToken(auth, session.firebaseToken)
.then(() => {
console.log(
"Successfully signed in with Firebase using custom token.",
);
})
.catch((error) => {
console.error("Error signing in with custom token:", error);
});
}
}, [session]);
...
Then i use trpc and drizzle in my nextjs app to fetch and query manipulate data from my planetscale database. Their is account, user, session, and verificationToken tables in my planetscale database. There is also a user showing up in the Firebase Auth UI, with a uid that is the same as their UID in my planetscale database user table. What is the implications if I now wanted to add an EXPO app? Would I use expo/react-native firebase package to sign in the user into Firebase only using custom token? Then use the Firebase UID returned to query the planetscale database from within my expo app? Would i need to interact with the nextauth database tables at all?
6 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 1/28/2024 in #questions
Why is there no SessionProvider wrapping app in next13+ app router boilerplate?
So can i add SessionProvider to a app directory app, so that I can use client side firebase hooks in my client componets? or should be only be using SessionProvider in nextjs^12 with pages directory?
7 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 1/9/2024 in #questions
How to find single record in database using trpc and drizzle?
I am still looking for an answer on how to use findfirst with drizzle so it returns a single array rather than an object. I cannot figure out how to use drizzle, findfirst, and a where clause...
11 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 1/9/2024 in #questions
How to find single record in database using trpc and drizzle?
I think i figured it out:
findUserByDiscordId: publicProcedure
.input(z.object({ discordId: z.string() }))
.query(({ ctx, input }) => {
const data = ctx.db
.select()
.from(users)
.where(eq(users.discordId, input.discordId))
return data;
}),
findUserByDiscordId: publicProcedure
.input(z.object({ discordId: z.string() }))
.query(({ ctx, input }) => {
const data = ctx.db
.select()
.from(users)
.where(eq(users.discordId, input.discordId))
return data;
}),
11 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 1/8/2024 in #questions
How to?: Sign In With Ethereum and have a user record created?
If i do need to code in my own logic, would it look something like this, and should i go through a trpc route?:
async authorize(credentials, req) {
try {
const siwe = new SiweMessage(
JSON.parse(credentials?.message ?? "{}"),
);
const nextAuthUrl = new URL(process.env.NEXTAUTH_URL!);

const result = await siwe.verify({
signature: credentials?.signature ?? "",
domain: nextAuthUrl.host,
nonce: await getCsrfToken({ req }),
});

console.log("result", result);

if (result.success) {
// Check if the user with this Ethereum address already exists in the database
let user = await db.findUserByWalletId(siwe.address);

if (!user) {
// If the user doesn't exist, create a new user in the database
user = await db.createUser({ walletId: siwe.address });
}

return {
id: siwe.address,
...user, // Include additional user properties from the database
};
}
return null;
} catch (e) {
return null;
}
},
async authorize(credentials, req) {
try {
const siwe = new SiweMessage(
JSON.parse(credentials?.message ?? "{}"),
);
const nextAuthUrl = new URL(process.env.NEXTAUTH_URL!);

const result = await siwe.verify({
signature: credentials?.signature ?? "",
domain: nextAuthUrl.host,
nonce: await getCsrfToken({ req }),
});

console.log("result", result);

if (result.success) {
// Check if the user with this Ethereum address already exists in the database
let user = await db.findUserByWalletId(siwe.address);

if (!user) {
// If the user doesn't exist, create a new user in the database
user = await db.createUser({ walletId: siwe.address });
}

return {
id: siwe.address,
...user, // Include additional user properties from the database
};
}
return null;
} catch (e) {
return null;
}
},
5 replies
TTCTheo's Typesafe Cult
Created by Trader Launchpad on 1/8/2024 in #questions
How to?: Sign In With Ethereum and have a user record created?
...
declare module "next-auth" {
interface Session extends DefaultSession {
user: {
id: string;
// ...other properties
// role: UserRole;
} & DefaultSession["user"];
}
}

export const authOptions: NextAuthOptions = {
callbacks: {
session: ({ session, token }) => {
return {
...session,
user: {
...session.user,
id: token.sub,
},
};
},
jwt: ({ token, user }) => {
return {
...token,
user,
};
},
},
adapter: DrizzleAdapter(db, mysqlTable),
providers: [
DiscordProvider({
clientId: env.DISCORD_CLIENT_ID,
clientSecret: env.DISCORD_CLIENT_SECRET,
}),
CredentialsProvider({
name: "Ethereum",
credentials: {
message: {
label: "Message",
type: "text",
placeholder: "0x0",
},
signature: {
label: "Signature",
type: "text",
placeholder: "0x0",
},
},
async authorize(credentials, req) {
try {
console.log("siwe step 1");
const siwe = new SiweMessage(
JSON.parse(credentials?.message ?? "{}"),
);
const nextAuthUrl = new URL(process.env.NEXTAUTH_URL!);

const result = await siwe.verify({
signature: credentials?.signature ?? "",
domain: nextAuthUrl.host,
nonce: await getCsrfToken({ req }),
});

console.log("result", result);

if (result.success) {
return {
id: siwe.address,
};
}
return null;
} catch (e) {
return null;
}
},
}),
],
session: { strategy: "jwt" },
};
export const getServerAuthSession = () => getServerSession(authOptions);
...
declare module "next-auth" {
interface Session extends DefaultSession {
user: {
id: string;
// ...other properties
// role: UserRole;
} & DefaultSession["user"];
}
}

export const authOptions: NextAuthOptions = {
callbacks: {
session: ({ session, token }) => {
return {
...session,
user: {
...session.user,
id: token.sub,
},
};
},
jwt: ({ token, user }) => {
return {
...token,
user,
};
},
},
adapter: DrizzleAdapter(db, mysqlTable),
providers: [
DiscordProvider({
clientId: env.DISCORD_CLIENT_ID,
clientSecret: env.DISCORD_CLIENT_SECRET,
}),
CredentialsProvider({
name: "Ethereum",
credentials: {
message: {
label: "Message",
type: "text",
placeholder: "0x0",
},
signature: {
label: "Signature",
type: "text",
placeholder: "0x0",
},
},
async authorize(credentials, req) {
try {
console.log("siwe step 1");
const siwe = new SiweMessage(
JSON.parse(credentials?.message ?? "{}"),
);
const nextAuthUrl = new URL(process.env.NEXTAUTH_URL!);

const result = await siwe.verify({
signature: credentials?.signature ?? "",
domain: nextAuthUrl.host,
nonce: await getCsrfToken({ req }),
});

console.log("result", result);

if (result.success) {
return {
id: siwe.address,
};
}
return null;
} catch (e) {
return null;
}
},
}),
],
session: { strategy: "jwt" },
};
export const getServerAuthSession = () => getServerSession(authOptions);
5 replies
TTCTheo's Typesafe Cult
Created by Tribe on 12/25/2023 in #questions
Adding Supabase to TRPC context
it should work locally with the edge runtime? on every t3 app I have worked in it always gives me errors developing locally with runtime=edge, on my windows pc and macbook :/
11 replies