diff --git a/bun.lock b/bun.lock index 7cf8d40..bb54b58 100644 --- a/bun.lock +++ b/bun.lock @@ -11,7 +11,7 @@ "@profullstack/libsql-pg": "^0.1.4", "@profullstack/openprofile": "^0.2.0", "@profullstack/player": "0.16.0", - "@profullstack/profile": "0.1.6", + "@profullstack/profile": "0.1.7", "@profullstack/scraper-daemon": "0.3.0", "@profullstack/submit-feed": "^0.1.3", "@profullstack/throttle": "^0.4.1", @@ -207,7 +207,7 @@ "@profullstack/player": ["@profullstack/player@0.16.0", "", { "dependencies": { "hls.js": "^1.7.1", "mpegts.js": "^1.8.2" }, "peerDependencies": { "react": ">=18" }, "optionalPeers": ["react"] }, "sha512-So56P59jh0wCd5gKKa0EIxBZGHm3WKqQGC+uW4N2nCz/heb2+kPQgH4YTJueJXcxwtXpf+Zb1/CWsoxWskfvAA=="], - "@profullstack/profile": ["@profullstack/profile@0.1.6", "", { "peerDependencies": { "@libsql/client": ">=0.6.0", "postgres": "^3.4.0", "react": ">=18" }, "optionalPeers": ["@libsql/client", "postgres", "react"], "bin": { "profile": "src/cli.js" } }, "sha512-xkn0P3ANz151QJdlBwcBXkHk813qW9qAmuTZKcuvpEZYkyHDC9J9KfvpVSRepfjECzz4ONGHWO5Zwc4BHpfK8g=="], + "@profullstack/profile": ["@profullstack/profile@0.1.7", "", { "dependencies": { "@profullstack/openprofile": "^0.2.0" }, "peerDependencies": { "@libsql/client": ">=0.6.0", "postgres": "^3.4.0", "react": ">=18" }, "optionalPeers": ["@libsql/client", "postgres", "react"], "bin": { "profile": "src/cli.js" } }, "sha512-N7UkypkkY2JkSBKzmdmyy6+DCoxI048qUZQksEjSRwSIyy4mjU9H1qW4yhZD+LJBhTEupgJv//Uxwhiy2FuGmA=="], "@profullstack/scraper-daemon": ["@profullstack/scraper-daemon@0.3.0", "", { "peerDependencies": { "bullmq": ">=6", "ioredis": ">=5" }, "optionalPeers": ["bullmq", "ioredis"], "bin": { "scraper-daemon": "bin/scraper-daemon.js" } }, "sha512-C/COc8Oef+/8/Bdu/uyvTZbeIO0rMm3q7wEJNzDqcuoZ+cEs6OEGzrKwCkA1N7zqyi3NASCAytfeFxJiiaG9TQ=="], diff --git a/package.json b/package.json index 816cbce..0e1d8f7 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@profullstack/libsql-pg": "^0.1.4", "@profullstack/openprofile": "^0.2.0", "@profullstack/player": "0.16.0", - "@profullstack/profile": "0.1.6", + "@profullstack/profile": "0.1.7", "@profullstack/scraper-daemon": "0.3.0", "@profullstack/submit-feed": "^0.1.3", "@profullstack/throttle": "^0.4.1", diff --git a/src/app/api/v1/coinpay/oauth/callback/route.ts b/src/app/api/v1/coinpay/oauth/callback/route.ts index 99e76aa..38330e1 100644 --- a/src/app/api/v1/coinpay/oauth/callback/route.ts +++ b/src/app/api/v1/coinpay/oauth/callback/route.ts @@ -1,4 +1,6 @@ import { cookies } from "next/headers"; +import { saveOpenProfileContact } from "@profullstack/profile"; +import { profileStore } from "@/lib/profile"; import { finishSignIn, sameState } from "@profullstack/coinpay-onboard/oauth"; import { currentUser, startSession } from "@/lib/auth/session"; import { @@ -59,6 +61,10 @@ export async function GET(req: Request) { dbCoinpayStore(), ); if (!result.ok) return fail(result.code); + if (pending.mode === "connect" && claims.openprofile_url) { + try { await saveOpenProfileContact(profileStore(), String(result.userId), claims.openprofile_url); } + catch { console.warn("[coinpay] OpenProfile import skipped"); } + } if (pending.mode === "connect") return back("/account?coinpay=connected"); await startSession(result.userId); diff --git a/src/components/ProfileForm.tsx b/src/components/ProfileForm.tsx index cef1d5e..fcba9ba 100644 --- a/src/components/ProfileForm.tsx +++ b/src/components/ProfileForm.tsx @@ -45,7 +45,7 @@ export default function ProfileForm({ initial }: { initial: Values }) { return (
- + diff --git a/src/lib/auth/coinpay.ts b/src/lib/auth/coinpay.ts index 40c66a3..62d7bbe 100644 --- a/src/lib/auth/coinpay.ts +++ b/src/lib/auth/coinpay.ts @@ -89,7 +89,7 @@ export function decodePending(raw: string | undefined): PendingAuth | null { } } -export type CoinpayClaims = { sub: string; email: string | null; name: string | null }; +export type CoinpayClaims = { sub: string; email: string | null; name: string | null; openprofile_url?: string }; export type IdentityRow = { user_id: number; @@ -190,10 +190,11 @@ export function canDisconnect(user: { email: string }, passkeyCount: number): bo } /** Trims what userinfo returned to what is stored; the email is contact info only. */ -export function claimsFrom(r: { sub: string; email: string | null; name: string | null }): CoinpayClaims { +export function claimsFrom(r: { sub: string; email: string | null; name: string | null; userinfo?: object }): CoinpayClaims { const email = typeof r.email === "string" && r.email.includes("@") ? r.email.slice(0, 320) : null; const name = typeof r.name === "string" && r.name.trim() ? r.name.trim().slice(0, 200) : null; - return { sub: r.sub, email, name }; + const userinfo = r.userinfo as { openprofile_url?: unknown } | undefined; + return { sub: r.sub, email, name, ...(typeof userinfo?.openprofile_url === "string" ? { openprofile_url: userinfo.openprofile_url } : {}) }; } const MESSAGES: Record = {