mey
mey
TTCTheo's Typesafe Cult
Created by mey on 2/11/2024 in #questions
Really obscure TypeError when starting Next.js
I have zero clue what's causing this but i just cloned my project on my mac after having developed it on windows for some time and i literally can't start the dev server due to this error, none of my pages load, and if i do not resolve this I will not meet the project deadline. here's a hastebin because discord bad https://hasteb.in/F3PcqE4BWtMopGQ
16 replies
TTCTheo's Typesafe Cult
Created by mey on 8/16/2023 in #questions
Regular Hexagon Plane using BufferGeometry in React Three Fiber
Pretty self explanatory but i can't seem to wrap my head around this one last bit. I have all the math for the vertices properly done but it seems like there's just this middle bit missing and I can't for the life of me figure out why (image attached) https://i-work-at-the.cocaine.institute/Lizzy64dd1efeWvDArpZ3jKuW.png My code for the HexTile component:
import { ThreeElements } from "@react-three/fiber";
import { type FC, type PropsWithChildren, useRef, useState, useMemo } from "react";
import { Vector3, DoubleSide } from "three";
import { HexCoordProps } from "../../lib/hex";
import { MAP_HEIGHT } from "../../lib/map";

export type HexTileProps = {
// todo
} & HexCoordProps & ThreeElements['group'] & PropsWithChildren;

const HexTile: FC<HexTileProps> = ({ children, q = 0, r = 0, ...props }) => {
const hexRef = useRef<THREE.Mesh>(null!);
const [hovered, setHovered] = useState(false);

const vertices: Vector3[] = [];
for (var i = 0; i < 6; ++i) {
// generate vertices of a perfect hexagonal plane based on a center point (q, r) and radius
const angle = (i / 6) * Math.PI * 2;
const x = q + 1 * Math.cos(angle);
const z = r + 1 * Math.sin(angle);
vertices.push(new Vector3(x, MAP_HEIGHT, z));
}

const memoizeVertices = useMemo(() => {
return Float32Array.from(
new Array(vertices.length)
.fill(0)
.flatMap((_, index) => vertices[index].toArray()));
}, [q, r])

return (
<group {...props} position={[q, MAP_HEIGHT, r]}>
<mesh
ref={hexRef}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
<bufferGeometry attach="geometry">
<bufferAttribute
args={[memoizeVertices, 7]}
attach={"attributes-position"}
itemSize={3}
count={vertices.length}
/>
</bufferGeometry>
<meshBasicMaterial attach="material" side={DoubleSide} color={hovered ? '#85e6c5': '#c8ffe0'} />
</mesh>
{children}
</group>
);
};

export default HexTile;
import { ThreeElements } from "@react-three/fiber";
import { type FC, type PropsWithChildren, useRef, useState, useMemo } from "react";
import { Vector3, DoubleSide } from "three";
import { HexCoordProps } from "../../lib/hex";
import { MAP_HEIGHT } from "../../lib/map";

export type HexTileProps = {
// todo
} & HexCoordProps & ThreeElements['group'] & PropsWithChildren;

const HexTile: FC<HexTileProps> = ({ children, q = 0, r = 0, ...props }) => {
const hexRef = useRef<THREE.Mesh>(null!);
const [hovered, setHovered] = useState(false);

const vertices: Vector3[] = [];
for (var i = 0; i < 6; ++i) {
// generate vertices of a perfect hexagonal plane based on a center point (q, r) and radius
const angle = (i / 6) * Math.PI * 2;
const x = q + 1 * Math.cos(angle);
const z = r + 1 * Math.sin(angle);
vertices.push(new Vector3(x, MAP_HEIGHT, z));
}

const memoizeVertices = useMemo(() => {
return Float32Array.from(
new Array(vertices.length)
.fill(0)
.flatMap((_, index) => vertices[index].toArray()));
}, [q, r])

return (
<group {...props} position={[q, MAP_HEIGHT, r]}>
<mesh
ref={hexRef}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
<bufferGeometry attach="geometry">
<bufferAttribute
args={[memoizeVertices, 7]}
attach={"attributes-position"}
itemSize={3}
count={vertices.length}
/>
</bufferGeometry>
<meshBasicMaterial attach="material" side={DoubleSide} color={hovered ? '#85e6c5': '#c8ffe0'} />
</mesh>
{children}
</group>
);
};

export default HexTile;
Also, an R3F tag would be cool for those that know it and three well to find and answer questions.
2 replies
TTCTheo's Typesafe Cult
Created by mey on 1/18/2023 in #questions
Prisma: filter include statement by nullable relation, exclude when null
I have the following code, being used to get a cart on a user session.
type CartType = Cart & { items: (Item & { product: Product })[] };

const getCart = async (ctx: Context): Promise<CartType> => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}

let cart: CartType;

if (ctx.session.cartId) {
cart = await ctx.prisma.cart.findUniqueOrThrow({
where: {
id: ctx.session.cartId
},
include: {
items: {
where: {
product: {
isNot: null,
},
},
include: {
product: true,
},
}
}
});
} else {
cart = await ctx.prisma.cart.create({
data: {},
include: {
items: {
where: {
product: {
isNot: null,
},
},
include: {
product: true,
},
},
},
});
}

return cart;
}
type CartType = Cart & { items: (Item & { product: Product })[] };

const getCart = async (ctx: Context): Promise<CartType> => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}

let cart: CartType;

if (ctx.session.cartId) {
cart = await ctx.prisma.cart.findUniqueOrThrow({
where: {
id: ctx.session.cartId
},
include: {
items: {
where: {
product: {
isNot: null,
},
},
include: {
product: true,
},
}
}
});
} else {
cart = await ctx.prisma.cart.create({
data: {},
include: {
items: {
where: {
product: {
isNot: null,
},
},
include: {
product: true,
},
},
},
});
}

return cart;
}
This results in the following error:
Type 'Cart & { items: (Item & { product: Product | null; })[]; }' is not assignable to type 'CartType'.
Type 'Cart & { items: (Item & { product: Product | null; })[]; }' is not assignable to type '{ items: (Item & { product: Product; })[]; }'.
Types of property 'items' are incompatible.
Type '(Item & { product: Product | null; })[]' is not assignable to type '(Item & { product: Product; })[]'.
Type 'Item & { product: Product | null; }' is not assignable to type 'Item & { product: Product; }'.
Type 'Item & { product: Product | null; }' is not assignable to type '{ product: Product; }'.
Types of property 'product' are incompatible.
Type 'Product | null' is not assignable to type 'Product'.
Type 'null' is not assignable to type 'Product'.ts(2322)
Type 'Cart & { items: (Item & { product: Product | null; })[]; }' is not assignable to type 'CartType'.
Type 'Cart & { items: (Item & { product: Product | null; })[]; }' is not assignable to type '{ items: (Item & { product: Product; })[]; }'.
Types of property 'items' are incompatible.
Type '(Item & { product: Product | null; })[]' is not assignable to type '(Item & { product: Product; })[]'.
Type 'Item & { product: Product | null; }' is not assignable to type 'Item & { product: Product; }'.
Type 'Item & { product: Product | null; }' is not assignable to type '{ product: Product; }'.
Types of property 'product' are incompatible.
Type 'Product | null' is not assignable to type 'Product'.
Type 'null' is not assignable to type 'Product'.ts(2322)
The items all need a product so that i can calculate a price. Unfortunately I have to work off an older schema as this is a rewrite of a site that was previously written using ASP.NET. The previous developer used the Item model for multiple purposes hence why it doesn't always correlate to a product, and instead sometimes to an order. I understand the problem here but cannot reach a solution that doesn't involve manually casting to the non-nullable type, which I'd like to try and avoid.
1 replies
TTCTheo's Typesafe Cult
Created by mey on 11/15/2022 in #questions
Websockets & Connection Upgrade on Next server
So i've been trying to bind a websocket connection from client to server on next, and i've done my usual server flow for this kind of shit:
import { NextApiRequest, NextApiResponse } from "next";
import { WebSocketServer } from 'ws';
import { getServerAuthSession } from "../../server/common/get-server-auth-session";
import socketHandler from "../../server/socket";

const socketBinder = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getServerAuthSession({ req, res });

if (session) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (res.socket.server.wss) {
console.log('Socket is already running')
} else {
console.log('Socket is initializing')
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const wss = new WebSocketServer({ server: res.socket.server })
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
res.socket.server.wss = wss
socketHandler(wss);
}
res.end()
} else res.end("Fuck off.");
}

export default socketBinder;
import { NextApiRequest, NextApiResponse } from "next";
import { WebSocketServer } from 'ws';
import { getServerAuthSession } from "../../server/common/get-server-auth-session";
import socketHandler from "../../server/socket";

const socketBinder = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getServerAuthSession({ req, res });

if (session) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (res.socket.server.wss) {
console.log('Socket is already running')
} else {
console.log('Socket is initializing')
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const wss = new WebSocketServer({ server: res.socket.server })
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
res.socket.server.wss = wss
socketHandler(wss);
}
res.end()
} else res.end("Fuck off.");
}

export default socketBinder;
and connected to it like so, with a context:
import { createContext, useContext, useMemo, useEffect, ReactNode } from 'react';

type WSProviderProps = { children: ReactNode; url: string };

const WSStateContext = createContext<WebSocket | null>(null);

function WSProvider({ children, url }: WSProviderProps): JSX.Element {
const wsInstance = useMemo(
() => (typeof window != 'undefined' ? new WebSocket(`ws${window.location.protocol === 'https:' ? 's' : ''}://${window.location.host}${url}`) : null),
[]
);

// useEffect(() => {
// return () => {
// wsInstance?.close();
// };
// }, []);

return <WSStateContext.Provider value={wsInstance}>{children}</WSStateContext.Provider>;
}

function useWS(): WebSocket {
const context = useContext(WSStateContext);

if (!context) {
throw new Error('useWS must be used within a WSProvider');
}

return context;
}

// elsewhere, in a page:

import { NextPage } from "next";
import Head from "next/head";
import { FC, useEffect } from "react";
import { WSProvider, useWS } from "../utils/ws";

const ChatView: FC = () => {
let ws: WebSocket;

if (typeof window !== 'undefined') ws = useWS();

useEffect(() => {
ws.onopen = (e: Event) => console.log(e);
})

return (
<>
{/* shit */}
</>
);
};

const ChatPage: NextPage = () => {
return (
<WSProvider url="/api/socket">
<Head>
<title>Iridium Chat</title>
</Head>

<main className="h-screen w-screen bg-gray-50 dark:bg-slate-900">
<ChatView />
</main>
</WSProvider>
);
}

export default ChatPage;
import { createContext, useContext, useMemo, useEffect, ReactNode } from 'react';

type WSProviderProps = { children: ReactNode; url: string };

const WSStateContext = createContext<WebSocket | null>(null);

function WSProvider({ children, url }: WSProviderProps): JSX.Element {
const wsInstance = useMemo(
() => (typeof window != 'undefined' ? new WebSocket(`ws${window.location.protocol === 'https:' ? 's' : ''}://${window.location.host}${url}`) : null),
[]
);

// useEffect(() => {
// return () => {
// wsInstance?.close();
// };
// }, []);

return <WSStateContext.Provider value={wsInstance}>{children}</WSStateContext.Provider>;
}

function useWS(): WebSocket {
const context = useContext(WSStateContext);

if (!context) {
throw new Error('useWS must be used within a WSProvider');
}

return context;
}

// elsewhere, in a page:

import { NextPage } from "next";
import Head from "next/head";
import { FC, useEffect } from "react";
import { WSProvider, useWS } from "../utils/ws";

const ChatView: FC = () => {
let ws: WebSocket;

if (typeof window !== 'undefined') ws = useWS();

useEffect(() => {
ws.onopen = (e: Event) => console.log(e);
})

return (
<>
{/* shit */}
</>
);
};

const ChatPage: NextPage = () => {
return (
<WSProvider url="/api/socket">
<Head>
<title>Iridium Chat</title>
</Head>

<main className="h-screen w-screen bg-gray-50 dark:bg-slate-900">
<ChatView />
</main>
</WSProvider>
);
}

export default ChatPage;
This only results in a pending handshake or a client error where it says i'm not in a context (the latter of which only happens when i leave out the useEffect and undefined check on the client) https://i-work-at-the.cocaine.institute/Lizzy6373b0daKzIbzcbyX5xU.png I've done the same deal with socket.io before with no problem and this seems to be the recommended way of doing this according to the google wtf is going on lol
7 replies
TTCTheo's Typesafe Cult
Created by mey on 10/8/2022 in #questions
Credentials Auth with tRPC
I'm rebuilding a client's site with the T3 stack. We originally had to do away with NextAuth because we figured its CredentialsProvider wasn't going to work for us. Then we moved to Strapi and after using Strapi I decided I'm just gonna do it myself. <Insert Thanos GIF> We still need to authenticate users based on username/password credentials, and I'm not sure how tRPC handles that within its ctx since according to NextAuth docs (https://next-auth.js.org/providers/credentials) it doesn't store session data in the DB.
12 replies