P-1953 Add Formo Analytics SDK examples across multiple frameworks#1
P-1953 Add Formo Analytics SDK examples across multiple frameworks#1
Conversation
Migrated 10 separate Formo SDK example repositories into a single monorepo following the resend/resend-examples flat collection pattern. Examples included: - with-react: React (CRA) with Formo Analytics - with-next-app-router: Next.js App Router (Scaffold-ETH 2) - with-next-page-router: Next.js Pages Router with RainbowKit - with-privy: Next.js with Privy embedded wallets - with-dynamic: React (Vite) with Dynamic.xyz wallet - with-reown: Next.js with Reown AppKit - with-porto: Next.js with Porto wallet - with-solana: Next.js with Solana wallet adapter - with-farcaster: Vite with Farcaster Mini App - with-react-native: React Native (Expo) Changes: - Added root .gitignore, README.md, LICENSE.md - Removed per-repo CI/CD workflows, git hooks, and contributing guides - Fixed local dependency references (file:../sdk, link:../sdk-react-native) to use published npm packages https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub. |
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Code fixes: - Fix operator precedence bug in utilsContract.tsx where "0_" + name || "tuple" never fell back to "tuple" - Remove dead code guard in farcaster main.tsx where || "demo_key" fallback made the null check unreachable README updates: - Update git clone URLs from old standalone repos to getformo/examples monorepo - Fix docs.formo.ai → docs.formo.so in with-react - Remove stale contribution/template sections from with-next-page-router that referenced CJskii/next-web3-template - Enhance with-farcaster README with Formo setup instructions - Remove stale local SDK development section from with-react-native (referenced old link:../sdk-react-native) - Update directory names in project structure sections https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
…rojectId - with-farcaster: pass wagmi config and queryClient to FormoAnalyticsProvider options so the SDK can auto-capture wallet events (connect, disconnect, etc.) - with-next-page-router: read WalletConnect projectId from NEXT_PUBLIC_REOWN_PROJECT_ID env var instead of hardcoded placeholder - with-next-page-router: add NEXT_PUBLIC_REOWN_PROJECT_ID to .env.example https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
Move FormoAnalyticsProvider inside WagmiProvider and QueryClientProvider to be consistent with the provider ordering used in with-dynamic, with-privy, with-reown, and all other examples in the monorepo. https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
Bumps @formo/analytics to the latest version in all 8 examples that were behind (with-dynamic, with-farcaster, with-next-page-router, with-porto, with-privy, with-react, with-reown, with-solana). with-next-app-router was already at ^1.27.0. https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
Ensures .env files are gitignored per-example so each example is self-contained when copied or cloned independently. Each .gitignore is tailored to its framework (Vite, Next.js, CRA, Expo). https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
Adds files from the upstream formo-example-next-app-router repo that were missing after migration to the monorepo: - .husky/pre-commit hook for lint-staged - .lintstagedrc.js (adapted for foundry instead of hardhat) - .github/workflows/lint.yaml for CI - CONTRIBUTING.md https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
The *.local glob already covers .env.local, .env.development.local, .env.test.local, and .env.production.local, making the specific patterns unnecessary. https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
Port three new examples from formo-example-* repos into the monorepo: - with-metamask: Next.js 15 + Wagmi + MetaMask SDK - with-thirdweb: Next.js 14 + Thirdweb v4 - with-web3-onboard: Next.js 15 + Web3 Onboard All updated to @formo/analytics ^1.27.0 with clean .gitignore and .env.example files. Removed local SDK path references from next.config files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- with-metamask: fix LogLevel[] type mismatch in logger.levels - with-farcaster: fix useSendCalls data rendering (use data.id), fix window.Buffer type assertion - with-solana: remove stale symlink, add type assertions for unpublished solana SDK types - with-privy: add force-dynamic to prevent SSG prerender with invalid Privy app ID - with-web3-onboard: escape apostrophes in JSX, remove unused analytics variable - with-next-app-router: add null check for publicClient in useTransactor hook - Update lockfiles for all examples after clean install 12 of 13 examples now build successfully. with-react-native is blocked on @formo/react-native-analytics not being published to npm. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| console.log('Tracking custom event:', eventName, parsedProperties); | ||
|
|
||
| // Send the track event using the useFormo hook | ||
| await analytics.track(eventName, parsedProperties); |
There was a problem hiding this comment.
Bug: The analytics object from useFormo() is used to call analytics.track() without a null check, risking a runtime error if the analytics SDK is not yet initialized.
Severity: MEDIUM
Suggested Fix
Add a null check before line 506 to ensure the analytics object is not null before attempting to call the track method. For example: if (!analytics) { setTrackError("Analytics not initialized"); return; }.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: with-farcaster/src/App.tsx#L506
Potential issue: The `analytics` instance is obtained from the `useFormo()` hook.
However, `analytics.track()` is called directly without verifying if the `analytics`
object is null or undefined. While the `FormoAnalyticsProvider` wraps the application,
the `useFormo()` hook could return a nullish value if the provider has not finished
initializing. This would cause a runtime error, "Cannot read property 'track' of null".
Although a `try-catch` block exists, it would only show a generic "Unknown tracking
error" instead of handling the uninitialized state gracefully. Other examples in the
codebase include this null check, indicating it's a necessary safeguard.
Runs `build` for each example in a parallel matrix on PRs and pushes to main. Auto-generates .env from .env.example with dummy CI values. Skips with-solana and with-react-native until their SDK versions are published. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
useFormo() can return undefined before the SDK finishes initializing. Adds a guard before calling analytics.track() to surface a clear error message instead of a cryptic runtime crash. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| functionName: abiFunction.name, | ||
| abi: abi, | ||
| args: getParsedContractFunctionArgs(form), | ||
| value: BigInt(txValue), |
There was a problem hiding this comment.
Bug: The code unconditionally calls BigInt(txValue). For non-payable functions, txValue is an empty string, which causes a SyntaxError runtime crash when the transaction is sent.
Severity: CRITICAL
Suggested Fix
The value parameter should only be included if the function is payable, or it should default to a safe value. For example, change BigInt(txValue) to BigInt(txValue || "0") to handle the empty string case.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location:
with-next-app-router/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx#L53
Potential issue: When a user interacts with a non-payable contract function, the
`txValue` state remains an empty string (`""`) because its corresponding input field is
not rendered. However, when the `handleWrite` function is called, it attempts to create
the transaction parameters with `value: BigInt(txValue)`. This results in `BigInt("")`,
which throws a `SyntaxError` and causes a runtime crash, preventing interaction with any
non-payable functions on the debug page.
- Fix BigInt("") SyntaxError in WriteOnlyFunctionForm for non-payable
contract functions by defaulting to BigInt(0)
- Use Node 22 for farcaster example (@farcaster/frame-sdk requires it)
- Use yarn --immutable for next-app-router (Yarn Berry, not classic)
- Write .env directly for next-app-router nested workspace instead of
copying from potentially missing root .env
- Add viem to with-react deps (CRA resolves all @formo/analytics
imports including wagmi module at build time)
- Use --legacy-peer-deps for with-thirdweb (react-query v4 vs v5
peer conflict)
- Set CI=false in build step to avoid CRA treating warnings as errors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Husky postinstall fails in CI because .git is at the repo root, not inside the example directory. Setting HUSKY=0 disables it. Also drop --immutable for Yarn Berry since the install was failing silently. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
||
| const handleIdentify = async () => { | ||
| if (!address) return; | ||
| await formo.identify({ |
There was a problem hiding this comment.
Bug: The formo object from useFormo() is used without checking if it's null. This could cause a crash if the SDK hasn't initialized yet.
Severity: HIGH
Suggested Fix
Before calling any methods on the formo object, add a check to ensure it is not null or undefined. For example: if (!formo) return; before calls like formo.track(...). This will prevent runtime errors during the SDK's initialization phase.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: with-porto/src/app/page.tsx#L395
Potential issue: The `formo` object, returned by the `useFormo()` hook, is used to call
methods like `formo.identify()`, `formo.track()`, and `formo.hasOptedOutTracking()`
without any null or undefined checks. Other examples within the same repository
defensively check if the `formo` object is initialized before use. Because some of these
calls, like in the `ConsentSection` `useEffect`, run automatically on component mount,
there is a race condition. If the Formo SDK has not finished initializing, `formo` will
be null or undefined, leading to a `TypeError` and a runtime crash.
TODOs
Summary
This PR adds comprehensive example applications demonstrating Formo Analytics SDK integration across multiple web3 and mobile frameworks. The examples showcase how to integrate Formo's analytics capabilities with various wallet solutions and development platforms.
Key Changes
New Example Applications
Core Features Demonstrated
Infrastructure & Configuration
Documentation
Notable Implementation Details
https://claude.ai/code/session_01Vth1WkLFrTqCTdjwZqFwby
Note
Low Risk
Primarily adds CI and example/docs files; low risk aside from potential CI failures from dependency/build matrix and env-file templating.
Overview
Adds a GitHub Actions workflow (
.github/workflows/build.yml) to build all example apps in CI via a matrix over directories, Node versions, and package managers, including basic.envgeneration from.env.exampleand a special-case nested env forwith-next-app-router.Bootstraps repo-level metadata (
.gitignore,LICENSE.md) and replaces the placeholder rootREADME.mdwith a catalog of the available examples.Introduces a new
with-dynamicVite/React example scaffold, including its env template, local ignores, and extensive README describing Formo + Dynamic.xyz integration (plus basic HTML entrypoint).Written by Cursor Bugbot for commit 784d7d8. This will update automatically on new commits. Configure here.