Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ jobs:
cd website
npm run lint

- name: Typecheck
run: |
cd website
npm run typecheck

- name: Test build
run: |
cd website
Expand Down
4 changes: 2 additions & 2 deletions comment_service/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import crypto from "crypto";

// ── Types ───────────────────────────────────────────────────────────────

interface ScalewayEvent {
export interface ScalewayEvent {
httpMethod: string;
headers?: Record<string, string>;
queryStringParameters?: Record<string, string>;
Expand All @@ -30,7 +30,7 @@ interface CommentPostBody {
website?: string; // honeypot field
}

interface HandlerResponse {
export interface HandlerResponse {
statusCode: number;
headers: Record<string, string>;
body: string;
Expand Down
3 changes: 2 additions & 1 deletion comment_service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"lint:fix": "eslint . --fix",
"format": "prettier --write \"**/*.{ts,js,json,md}\"",
"format:check": "prettier --check \"**/*.{ts,js,json,md}\"",
"check": "npm run lint && npm run format:check && npm run test:coverage",
"typecheck": "tsc --noEmit",
"check": "npm run lint && npm run format:check && npm run typecheck && npm run test:coverage",
"predeploy": "npm run build",
"deploy": "serverless deploy",
"info": "serverless info",
Expand Down
5 changes: 3 additions & 2 deletions comment_service/test/comments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { describe, test, expect, beforeAll, beforeEach, afterEach, vi } from "vitest";
import type { ScalewayEvent, HandlerResponse } from "../comments";

// Mock the shared S3 client
const mockListObjects = vi.fn();
Expand All @@ -19,10 +20,10 @@ vi.mock("@fretchen/s3-utils", () => ({
global.fetch = vi.fn() as any;

describe("comments.ts", () => {
let handle: (event: Record<string, any>, context: unknown) => Promise<any>;
let handle: (event: ScalewayEvent, context: unknown) => Promise<HandlerResponse>;

beforeAll(async () => {
const module = await import("../comments.ts");
const module = await import("../comments");
handle = module.handle;
});

Expand Down
3 changes: 2 additions & 1 deletion eth/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
},
"exclude": ["node_modules", "archive"]
}
3 changes: 2 additions & 1 deletion shared/chain-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
"scripts": {
"build": "tsc",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"format": "prettier --check .",
"format:fix": "prettier --write .",
"check": "npm run lint && npm run format && npm run test:coverage",
"check": "npm run lint && npm run format && npm run typecheck && npm run test:coverage",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
Expand Down
4 changes: 3 additions & 1 deletion website/components/FacilitatorApproval.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ export function FacilitatorApproval({
const [fetchError, setFetchError] = useState<string | null>(null);

const networks = showTestnets ? APPROVAL_NETWORKS_WITH_TESTNETS : APPROVAL_NETWORKS;
const [selectedNetwork, setSelectedNetwork] = useState(networks[0].network);
const [selectedNetwork, setSelectedNetwork] = useState<(typeof APPROVAL_NETWORKS_WITH_TESTNETS)[number]["network"]>(
networks[0].network,
);

const usdcConfig = getNetworkUSDCConfig(selectedNetwork);
const targetChainId = usdcConfig ? usdcConfig.chainId : fromCAIP2(selectedNetwork);
Expand Down
2 changes: 1 addition & 1 deletion website/components/ImageModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function ImageModal({ image, onClose }: ImageModalProps) {
{image.description && <p className={styles.nftCard.modalDescription}>{image.description}</p>}
{image.network && <ChainInfoDisplay network={image.network} tokenId={image.tokenId} />}
<div className={styles.nftCard.actions} style={{ justifyContent: "center", marginTop: "12px" }}>
<button onClick={handleDownload} className={`${styles.nftCard.actionButton} ${styles.primaryButton}`}>
<button onClick={handleDownload} className={`${styles.actionButton} ${styles.primaryButton}`}>
⬇️ Download Full Size
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion website/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function Link({
const { urlPathname } = pageContext;

if (!locale && pageContext.locale) {
locale = pageContext.locale as string;
locale = pageContext.locale;
}
if (!locale && !pageContext.locale) {
locale = defaultLocale;
Expand Down
7 changes: 3 additions & 4 deletions website/components/MarkdownWithLatex.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react";
import ReactMarkdown, { type Components } from "react-markdown";
import ReactMarkdown, { type Components, type Options } from "react-markdown";

interface MarkdownWithLatexProps {
children: string;
remarkPlugins?: unknown[];
remarkPlugins?: Options["remarkPlugins"];
components?: Partial<Components>;
}

Expand All @@ -20,10 +20,9 @@ export const MarkdownWithLatex: React.FC<MarkdownWithLatexProps> = ({ children,
// Client-side LaTeX rendering after content is mounted
React.useEffect(() => {
if (containerRef.current) {
type RenderMathInElement = (element: Element, options?: Record<string, unknown>) => void;
import("katex/dist/contrib/auto-render")
.then((module) => {
const renderMathInElement = (module as { default: RenderMathInElement }).default;
const renderMathInElement = module.default;
if (containerRef.current) {
renderMathInElement(containerRef.current, {
delimiters: [
Expand Down
2 changes: 1 addition & 1 deletion website/components/Post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { CommentsSection } from "./CommentsSection";
const ReactPostRenderer: React.FC<{
componentPath: string;
tokenID?: number;
contentRef: React.RefObject<HTMLDivElement>;
contentRef: React.RefObject<HTMLDivElement | null>;
onReady?: () => void;
}> = ({ componentPath, tokenID, contentRef, onReady }) => {
const [Component, setComponent] = React.useState<React.ComponentType | null>(null);
Expand Down
2 changes: 1 addition & 1 deletion website/components/SimpleCollectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export function SimpleCollectButton({ genImTokenId }: SimpleCollectButtonProps)
<button
onClick={handleCollect}
disabled={!isConnected || !simulateMintData || isPending || isConfirming || isLoading}
className={`${styles.nftCard.actionButton} ${styles.primaryButton}`}
className={`${styles.actionButton} ${styles.primaryButton}`}
title={`Collect this NFT (${getMintCount()} collected) | ${getPriceInfo()}`}
>
{isPending || isLoading
Expand Down
2 changes: 1 addition & 1 deletion website/components/TableOfContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { toc } from "../layouts/styles";

interface TableOfContentsProps {
/** Ref to the content container containing headings */
contentRef: RefObject<HTMLElement>;
contentRef: RefObject<HTMLElement | null>;
/** Minimum number of headings required to show ToC (default: 2) */
minHeadings?: number;
/** Title shown above the ToC (default: "On this page") */
Expand Down
4 changes: 2 additions & 2 deletions website/hooks/useConfiguredPublicClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo } from "react";
import { getPublicClient } from "wagmi/actions";
import { config } from "../wagmi.config";
import { config, asConfiguredChainId } from "../wagmi.config";
import { fromCAIP2 } from "@fretchen/chain-utils";

/**
Expand All @@ -15,7 +15,7 @@ import { fromCAIP2 } from "@fretchen/chain-utils";
*/
export function useConfiguredPublicClient(network: string) {
return useMemo(() => {
const chainId = fromCAIP2(network);
const chainId = asConfiguredChainId(fromCAIP2(network));
// Must pass chainId explicitly to get the correct chain's public client
return getPublicClient(config, { chainId });
}, [network]);
Expand Down
3 changes: 1 addition & 2 deletions website/hooks/useKaTeXRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ export function useKaTeXRenderer(containerRef: React.RefObject<HTMLElement | nul
// Delay to ensure content has fully rendered
const timer = setTimeout(() => {
// Dynamically import KaTeX only in the browser
type RenderMathInElement = (element: Element, options?: Record<string, unknown>) => void;
Promise.all([import("katex"), import("katex/dist/contrib/auto-render")])
.then(([katexModule, autoRenderModule]) => {
const katex = katexModule.default;
const renderMathInElement = (autoRenderModule as { default: RenderMathInElement }).default;
const renderMathInElement = autoRenderModule.default;

if (!containerRef.current) return;

Expand Down
6 changes: 3 additions & 3 deletions website/hooks/useMultiChainNFTs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useMemo } from "react";
import { useQuery } from "@tanstack/react-query";
import { useAccount } from "wagmi";
import { readContract } from "wagmi/actions";
import { config } from "../wagmi.config";
import { config, asConfiguredChainId } from "../wagmi.config";
import { getGenAiNFTAddress, GenImNFTv4ABI, GENAI_NFT_NETWORKS, fromCAIP2, isTestnet } from "@fretchen/chain-utils";

export interface MultiChainNFTToken {
Expand All @@ -23,7 +23,7 @@ interface UseMultiChainUserNFTsResult {

async function fetchUserTokensOnNetwork(network: string, address: `0x${string}`): Promise<MultiChainNFTToken[]> {
const contractAddress = getGenAiNFTAddress(network);
const chainId = fromCAIP2(network);
const chainId = asConfiguredChainId(fromCAIP2(network));

const balance = await readContract(config, {
address: contractAddress,
Expand Down Expand Up @@ -99,7 +99,7 @@ interface UseMultiChainPublicNFTsResult {

async function fetchPublicTokensOnNetwork(network: string): Promise<MultiChainNFTToken[]> {
const contractAddress = getGenAiNFTAddress(network);
const chainId = fromCAIP2(network);
const chainId = asConfiguredChainId(fromCAIP2(network));

const tokenIds = (await readContract(config, {
address: contractAddress,
Expand Down
4 changes: 2 additions & 2 deletions website/hooks/useNFTListedStatus.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { readContract } from "wagmi/actions";
import { config } from "../wagmi.config";
import { config, asConfiguredChainId } from "../wagmi.config";
import { getGenAiNFTAddress, GenImNFTv4ABI, fromCAIP2 } from "@fretchen/chain-utils";

export interface UseNFTListedStatusOptions {
Expand All @@ -24,7 +24,7 @@ export function useNFTListedStatus({
enabled = true,
}: UseNFTListedStatusOptions): UseNFTListedStatusResult {
const queryClient = useQueryClient();
const chainId = fromCAIP2(network);
const chainId = asConfiguredChainId(fromCAIP2(network));
const contractAddress = getGenAiNFTAddress(network);
const tokenIdStr = tokenId.toString();
const queryKey = ["nftListedStatus", tokenIdStr, network] as const;
Expand Down
2 changes: 1 addition & 1 deletion website/hooks/useTableOfContents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function slugify(text: string): string {
* const headings = useTableOfContents(contentRef);
* ```
*/
export function useTableOfContents(contentRef: RefObject<HTMLElement>, isReady: boolean = true): TocItem[] {
export function useTableOfContents(contentRef: RefObject<HTMLElement | null>, isReady: boolean = true): TocItem[] {
const [headings, setHeadings] = useState<TocItem[]>([]);

useEffect(() => {
Expand Down
1 change: 1 addition & 0 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"build:local": "vike build",
"postbuild": "tsx ./utils/cleanVike.ts && tsx ./utils/generateSitemap.ts && tsx ./utils/checkChunkSizes.ts",
"preview": "vike preview",
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"test": "vitest run",
Expand Down
2 changes: 2 additions & 0 deletions website/test/ContractChainSelection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ vi.mock("../wagmi.config", () => ({
chains: [],
transports: {},
},
asConfiguredChainId: (id: number) => id,
}));

vi.mock("wagmi/actions", () => ({
Expand All @@ -31,6 +32,7 @@ describe("Contract Chain Selection", () => {
const chain = getViemChain(network);
const client = getPublicClient({ ...config, chains: [chain] });
expect(client).toBeDefined();
if (!client) throw new Error("client should be defined");

// Try to read from contract using chain-utils
const contractAddress = getGenAiNFTAddress(network);
Expand Down
2 changes: 1 addition & 1 deletion website/test/FacilitatorApproval.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const MOCK_SUPPORTED_RESPONSE = {
const FACILITATOR_ADDRESS = "0xFacilitatorAddress1234567890123456789012";

describe("FacilitatorApproval", () => {
let mockWriteContract: ReturnType<typeof vi.fn>;
let mockWriteContract: ReturnType<typeof vi.fn<(...args: unknown[]) => unknown>>;

beforeEach(() => {
vi.clearAllMocks();
Expand Down
Loading
Loading