diff --git a/apps/web/package.json b/apps/web/package.json index c4da4105..9df11539 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -27,7 +27,7 @@ "@profullstack/live-translate": "^0.3.0", "@profullstack/notifications": "0.1.4", "@profullstack/pairux-embed": "workspace:*", - "@profullstack/profile": "0.1.6", + "@profullstack/profile": "0.1.7", "@profullstack/redeem-credits": "^0.2.0", "@profullstack/stack": "^0.5.0", "@profullstack/x402-gateway": "^0.13.1", diff --git a/apps/web/src/app/api/v1/coinpay/oauth/callback/route.ts b/apps/web/src/app/api/v1/coinpay/oauth/callback/route.ts index 05d27d42..65c8dcbf 100644 --- a/apps/web/src/app/api/v1/coinpay/oauth/callback/route.ts +++ b/apps/web/src/app/api/v1/coinpay/oauth/callback/route.ts @@ -2,6 +2,8 @@ import { createServerClient, type CookieOptions } from '@supabase/ssr'; import type { SupabaseClient } from '@supabase/supabase-js'; import { NextResponse, type NextRequest } from 'next/server'; import { finishSignIn, sameState } from '@profullstack/coinpay-onboard/oauth'; +import { saveOpenProfileContact } from '@profullstack/profile'; +import { profileStore } from '@/lib/profile'; import { createClient } from '@/lib/supabase/server'; import { serviceClient } from '@/lib/supabase/service'; import { @@ -80,6 +82,13 @@ export async function GET(request: NextRequest) { return fail('failed'); } if (!result.ok) return fail(result.code); + if (pending.mode === 'connect' && claims.openprofile_url) { + try { + await saveOpenProfileContact(profileStore(), result.userId, claims.openprofile_url); + } catch { + console.warn('[coinpay] OpenProfile import skipped'); + } + } if (pending.mode === 'connect') return go('/settings?coinpay=connected'); const minted = await mintMagicLinkHash(admin, result.userId); diff --git a/apps/web/src/components/profile/ProfileCard.tsx b/apps/web/src/components/profile/ProfileCard.tsx index cff15c90..25940359 100644 --- a/apps/web/src/components/profile/ProfileCard.tsx +++ b/apps/web/src/components/profile/ProfileCard.tsx @@ -73,6 +73,7 @@ export function ProfileCard() { onChange={setValues} errors={errors} disabled={!loaded} + importOpenProfile /> {error &&

{error}

}
diff --git a/apps/web/src/lib/coinpay-signin.ts b/apps/web/src/lib/coinpay-signin.ts index 695c5b46..4606e23a 100644 --- a/apps/web/src/lib/coinpay-signin.ts +++ b/apps/web/src/lib/coinpay-signin.ts @@ -149,6 +149,7 @@ export interface CoinpayClaims { sub: string; email: string | null; name: string | null; + openprofile_url?: string; } /** Trim what CoinPay returned to what is stored; the email is contact info only. */ @@ -156,10 +157,17 @@ 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 openprofileUrl = (r.userinfo as { openprofile_url?: unknown } | undefined)?.openprofile_url; + return { + sub: r.sub, + email, + name, + ...(typeof openprofileUrl === 'string' ? { openprofile_url: openprofileUrl } : {}), + }; } export interface IdentityRow { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 90c2fcdc..3ba1f0f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -399,7 +399,7 @@ importers: version: 1.0.3 '@profullstack/footer': specifier: latest - version: 0.5.0(react@19.3.1) + version: 0.6.15(react@19.3.1) '@profullstack/live-translate': specifier: ^0.3.0 version: 0.3.0 @@ -410,8 +410,8 @@ importers: specifier: workspace:* version: link:../../packages/embed '@profullstack/profile': - specifier: 0.1.6 - version: 0.1.6(react@19.3.1) + specifier: 0.1.7 + version: 0.1.7(react@19.3.1) '@profullstack/redeem-credits': specifier: ^0.2.0 version: 0.2.0 @@ -3007,8 +3007,8 @@ packages: react: optional: true - '@profullstack/footer@0.5.0': - resolution: {integrity: sha512-TrllS87nK7J0c/UgYckaFIWVhLOtr6m73XXFSHIuSfOg7NfuWUdwjtsfMXGaZiiUnmMYj3zhGcfzW0DicDwl8w==} + '@profullstack/footer@0.6.15': + resolution: {integrity: sha512-kkkSG8Xw0VnyzYk76ko0aiIgVT/MXmKkKUiJ5u1DZkeLZcDh0d2GjFShwTcCd8AsQr5fBet39wbzSwPeUYwuWg==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -3033,8 +3033,12 @@ packages: resolution: {integrity: sha512-4RSq9C4ghgf/W1YGK6Ai9oMJWWLW2WOSn8cl/J7tbdK/c8nhIr3z3BjQcYJyjGGIMdRuUBGVBAJmp3uAtY28+A==} engines: {node: '>=20.11'} - '@profullstack/profile@0.1.6': - resolution: {integrity: sha512-xkn0P3ANz151QJdlBwcBXkHk813qW9qAmuTZKcuvpEZYkyHDC9J9KfvpVSRepfjECzz4ONGHWO5Zwc4BHpfK8g==} + '@profullstack/openprofile@0.2.0': + resolution: {integrity: sha512-cdFsBbfRXurvy5KqHDNcKXxurK2s/YlfVgnILFRpVl2hq3860rExqDee8IfsFGxw5cPdqGv2fxUxtek1Xy2U5Q==} + engines: {node: '>=22'} + + '@profullstack/profile@0.1.7': + resolution: {integrity: sha512-N7UkypkkY2JkSBKzmdmyy6+DCoxI048qUZQksEjSRwSIyy4mjU9H1qW4yhZD+LJBhTEupgJv//Uxwhiy2FuGmA==} engines: {node: '>=20'} hasBin: true peerDependencies: @@ -12531,7 +12535,7 @@ snapshots: optionalDependencies: react: 19.3.1 - '@profullstack/footer@0.5.0(react@19.3.1)': + '@profullstack/footer@0.6.15(react@19.3.1)': optionalDependencies: react: 19.3.1 @@ -12543,7 +12547,11 @@ snapshots: '@profullstack/notifications@0.1.4': {} - '@profullstack/profile@0.1.6(react@19.3.1)': + '@profullstack/openprofile@0.2.0': {} + + '@profullstack/profile@0.1.7(react@19.3.1)': + dependencies: + '@profullstack/openprofile': 0.2.0 optionalDependencies: react: 19.3.1