module.exports = [
"[externals]/crypto [external] (crypto, cjs)", ((__turbopack_context__, module, exports) => {

var mod = __turbopack_context__.x("crypto", () => require("crypto"));

module.exports = mod;
}),
"[externals]/next/dist/shared/lib/no-fallback-error.external.js [external] (next/dist/shared/lib/no-fallback-error.external.js, cjs)", ((__turbopack_context__, module, exports) => {

var mod = __turbopack_context__.x("next/dist/shared/lib/no-fallback-error.external.js", () => require("next/dist/shared/lib/no-fallback-error.external.js"));

module.exports = mod;
}),
"[project]/src/app/favicon.ico (static in ecmascript, tag client)", ((__turbopack_context__) => {

__turbopack_context__.v("/_next/static/media/favicon.2vob68tjqpejf.ico" + (globalThis["NEXT_CLIENT_ASSET_SUFFIX"] || ''));}),
"[project]/src/app/favicon.ico.mjs { IMAGE => \"[project]/src/app/favicon.ico (static in ecmascript, tag client)\" } [app-rsc] (structured image object, ecmascript)", ((__turbopack_context__) => {
"use strict";

__turbopack_context__.s([
    "default",
    ()=>__TURBOPACK__default__export__
]);
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$app$2f$favicon$2e$ico__$28$static__in__ecmascript$2c$__tag__client$29$__ = __turbopack_context__.i("[project]/src/app/favicon.ico (static in ecmascript, tag client)");
;
const __TURBOPACK__default__export__ = {
    src: __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$app$2f$favicon$2e$ico__$28$static__in__ecmascript$2c$__tag__client$29$__["default"],
    width: 256,
    height: 256
};
}),
"[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

return __turbopack_context__.a(async (__turbopack_handle_async_dependencies__, __turbopack_async_result__) => { try {
__turbopack_context__.s([
    "default",
    ()=>ProfilePage
]);
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/rsc/react-jsx-dev-runtime.js [app-rsc] (ecmascript)");
// Person profile page (T-507). REQ-PROF-001/002.
//
// Server Component: unlike every prior page under
// src/app/trahs/[trahId]/persons/[personId]/** (edit, claim — both gate the
// whole page behind a login redirect via getCallerMembership), this page's
// underlying contract function, getProfile(), has an OPTIONAL
// viewerMembershipId — null/omitted is a documented, in-scope PUBLIC view
// (REQ-ID-004; see getProfile.ts's header comment for why). So this page
// calls getCallerMembership(trahId) but does NOT redirect-to-login when it
// resolves to null — it passes null straight through to getProfile, and an
// unauthenticated or non-member visitor still gets whatever PUBLIC-only
// fields getProfile itself already filtered down to (name + life status,
// no gender, no facts/residences/relationships, PUBLIC contacts only).
// This page never re-applies privacy filtering of its own — it renders
// exactly what getProfile returns.
//
// --- Judgment calls (flagged for reviewer) --------------------------------
//
// 1. Route: chosen as .../persons/[personId]/profile (not bare
//    .../persons/[personId]) to keep it a sibling of edit/ and claim/ under
//    the same personId segment, rather than colliding with a future index
//    route at that path. Consistent going forward for any links added here
//    or in other pages.
//
// 2. Claim badge (REQ-PROF-002): resolved per the ticket's option (a) — a
//    second, separate call to isPersonClaimed(prisma, trahId, personId),
//    made ONLY when the viewer is an active member (isPersonClaimed leaks
//    which userId claimed a Person, which is FAMILY-level information, not
//    PUBLIC — an unauthenticated/non-member viewer never triggers this
//    query or sees its result). This resolves WORKPLAN.md's previously
//    flagged "ProfileView has no REQ-PROF-002 claim badge yet" gap (T-305)
//    now that T-204's isPersonClaimed exists — WORKPLAN.md updated
//    accordingly instead of leaving the old note stale.
//
// 3. Disputed facts (REQ-ID-005 "disputed data shown side by side"):
//    getProfile returns the full, unreduced facts array (no isPreferred
//    collapsing) — this page renders every fact row as-is, grouped by
//    field, so two facts for the same field (e.g. two different birth
//    dates, still under dispute) both show rather than one being silently
//    dropped. isPreferred is shown as a small tag, not used as a filter.
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$api$2f$navigation$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__$3c$locals$3e$__ = __turbopack_context__.i("[project]/node_modules/next/dist/api/navigation.react-server.js [app-rsc] (ecmascript) <locals>");
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$components$2f$navigation$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/next/dist/client/components/navigation.react-server.js [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$app$2d$dir$2f$link$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/next/dist/client/app-dir/link.react-server.js [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/lib/prisma.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$get$2d$caller$2d$membership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/lib/get-caller-membership.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$canWrite$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/trah-membership/canWrite.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$isPersonClaimed$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/trah-membership/isPersonClaimed.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$genealogy$2f$getProfile$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/genealogy/getProfile.ts [app-rsc] (ecmascript)");
var __turbopack_async_dependencies__ = __turbopack_handle_async_dependencies__([
    __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__,
    __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$get$2d$caller$2d$membership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__
]);
[__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$get$2d$caller$2d$membership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__] = __turbopack_async_dependencies__.then ? (await __turbopack_async_dependencies__)() : __turbopack_async_dependencies__;
;
;
;
;
;
;
;
;
function groupFactsByField(facts) {
    const grouped = new Map();
    for (const fact of facts){
        const existing = grouped.get(fact.field);
        if (existing) {
            existing.push(fact);
        } else {
            grouped.set(fact.field, [
                fact
            ]);
        }
    }
    return grouped;
}
function RelationList({ trahId, title, people }) {
    if (people.length === 0) return null;
    return /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("section", {
        children: [
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("h2", {
                children: title
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 75,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("ul", {
                children: people.map((p)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("li", {
                        children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$app$2d$dir$2f$link$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["default"], {
                            href: `/trahs/${trahId}/persons/${p.id}/profile`,
                            children: p.displayName
                        }, void 0, false, {
                            fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                            lineNumber: 79,
                            columnNumber: 13
                        }, this)
                    }, p.id, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 78,
                        columnNumber: 11
                    }, this))
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 76,
                columnNumber: 7
            }, this)
        ]
    }, void 0, true, {
        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
        lineNumber: 74,
        columnNumber: 5
    }, this);
}
async function ProfilePage({ params }) {
    const { trahId, personId } = await params;
    // No login redirect here — a null caller is the documented PUBLIC-view
    // path (see file header). Every other page under persons/[personId]/**
    // redirects; this one intentionally doesn't.
    const caller = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$get$2d$caller$2d$membership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["getCallerMembership"])(trahId);
    const profile = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$genealogy$2f$getProfile$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["getProfile"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], trahId, personId, caller?.membershipId ?? null);
    if (!profile) {
        (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$components$2f$navigation$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["notFound"])();
    }
    const isMember = !!caller;
    const [writable, claimStatus] = await Promise.all([
        isMember ? (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$canWrite$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["canWrite"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], caller.membershipId) : Promise.resolve(false),
        isMember ? (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$isPersonClaimed$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["isPersonClaimed"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], trahId, personId) : Promise.resolve(null)
    ]);
    const factsByField = groupFactsByField(profile.facts);
    return /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("main", {
        style: {
            maxWidth: 640,
            margin: "0 auto",
            padding: "2rem 1rem"
        },
        children: [
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("h1", {
                children: profile.displayName
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 114,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("p", {
                children: [
                    profile.gender ? `Gender: ${profile.gender} · ` : "",
                    "Life status: ",
                    profile.lifeStatus
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 115,
                columnNumber: 7
            }, this),
            isMember && claimStatus && /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("p", {
                children: claimStatus.claimed ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["Fragment"], {
                    children: "✓ Claimed"
                }, void 0, false, {
                    fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                    lineNumber: 123,
                    columnNumber: 13
                }, this) : /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["Fragment"], {
                    children: [
                        "Unclaimed —",
                        " ",
                        /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$app$2d$dir$2f$link$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["default"], {
                            href: `/trahs/${trahId}/persons/${personId}/claim`,
                            children: "is this you?"
                        }, void 0, false, {
                            fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                            lineNumber: 127,
                            columnNumber: 15
                        }, this)
                    ]
                }, void 0, true, {
                    fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                    lineNumber: 125,
                    columnNumber: 13
                }, this)
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 121,
                columnNumber: 9
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("p", {
                children: [
                    /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$app$2d$dir$2f$link$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["default"], {
                        href: `/trahs/${trahId}/tree?root=${personId}`,
                        children: "View in family tree"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 134,
                        columnNumber: 9
                    }, this),
                    writable && /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["Fragment"], {
                        children: [
                            " · ",
                            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$app$2d$dir$2f$link$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["default"], {
                                href: `/trahs/${trahId}/persons/${personId}/edit`,
                                children: "Edit"
                            }, void 0, false, {
                                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                lineNumber: 138,
                                columnNumber: 13
                            }, this)
                        ]
                    }, void 0, true, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 136,
                        columnNumber: 11
                    }, this),
                    isMember && /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["Fragment"], {
                        children: [
                            " · ",
                            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$client$2f$app$2d$dir$2f$link$2e$react$2d$server$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["default"], {
                                href: `/trahs/${trahId}/persons/${personId}/history`,
                                children: "View history"
                            }, void 0, false, {
                                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                lineNumber: 144,
                                columnNumber: 13
                            }, this)
                        ]
                    }, void 0, true, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 142,
                        columnNumber: 11
                    }, this)
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 133,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("section", {
                children: [
                    /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("h2", {
                        children: "Facts"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 150,
                        columnNumber: 9
                    }, this),
                    factsByField.size === 0 ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("p", {
                        children: "No facts recorded, or not visible to you."
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 152,
                        columnNumber: 11
                    }, this) : /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("ul", {
                        children: [
                            ...factsByField.entries()
                        ].map(([field, facts])=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("li", {
                                children: [
                                    /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("strong", {
                                        children: field
                                    }, void 0, false, {
                                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                        lineNumber: 157,
                                        columnNumber: 17
                                    }, this),
                                    /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("ul", {
                                        children: facts.map((fact)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("li", {
                                                children: [
                                                    JSON.stringify(fact.value),
                                                    fact.precisionQualifier ? ` (${fact.precisionQualifier})` : "",
                                                    " —",
                                                    " ",
                                                    fact.verificationStatus,
                                                    fact.isPreferred ? " · preferred" : "",
                                                    fact.source ? ` — source: ${fact.source}` : ""
                                                ]
                                            }, fact.id, true, {
                                                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                                lineNumber: 160,
                                                columnNumber: 21
                                            }, this))
                                    }, void 0, false, {
                                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                        lineNumber: 158,
                                        columnNumber: 17
                                    }, this)
                                ]
                            }, field, true, {
                                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                lineNumber: 156,
                                columnNumber: 15
                            }, this))
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 154,
                        columnNumber: 11
                    }, this)
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 149,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("section", {
                children: [
                    /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("h2", {
                        children: "Residences"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 176,
                        columnNumber: 9
                    }, this),
                    profile.residences.length === 0 ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("p", {
                        children: "No residences recorded, or not visible to you."
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 178,
                        columnNumber: 11
                    }, this) : /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("ul", {
                        children: profile.residences.map((r)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("li", {
                                children: [
                                    r.place,
                                    " — ",
                                    r.startDate.toISOString().slice(0, 10),
                                    r.endDate ? ` to ${r.endDate.toISOString().slice(0, 10)}` : r.isCurrent ? " (current)" : ""
                                ]
                            }, r.id, true, {
                                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                lineNumber: 182,
                                columnNumber: 15
                            }, this))
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 180,
                        columnNumber: 11
                    }, this)
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 175,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("section", {
                children: [
                    /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("h2", {
                        children: "Contacts"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 196,
                        columnNumber: 9
                    }, this),
                    profile.contacts.length === 0 ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("p", {
                        children: "No contacts visible to you."
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 198,
                        columnNumber: 11
                    }, this) : /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("ul", {
                        children: profile.contacts.map((c)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])("li", {
                                children: [
                                    c.type,
                                    ": ",
                                    c.value,
                                    " (",
                                    c.visibility,
                                    ")"
                                ]
                            }, c.id, true, {
                                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                                lineNumber: 202,
                                columnNumber: 15
                            }, this))
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                        lineNumber: 200,
                        columnNumber: 11
                    }, this)
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 195,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(RelationList, {
                trahId: trahId,
                title: "Parents",
                people: profile.parents
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 210,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(RelationList, {
                trahId: trahId,
                title: "Partners",
                people: profile.partners
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 211,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(RelationList, {
                trahId: trahId,
                title: "Children",
                people: profile.children
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 212,
                columnNumber: 7
            }, this),
            /*#__PURE__*/ (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$rsc$2f$react$2d$jsx$2d$dev$2d$runtime$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["jsxDEV"])(RelationList, {
                trahId: trahId,
                title: "Siblings",
                people: profile.siblings
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
                lineNumber: 213,
                columnNumber: 7
            }, this)
        ]
    }, void 0, true, {
        fileName: "[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx",
        lineNumber: 113,
        columnNumber: 5
    }, this);
}
__turbopack_async_result__();
} catch(e) { __turbopack_async_result__(e); } }, false);}),
"[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx [app-rsc] (ecmascript, Next.js Server Component)", (function(__turbopack_context__){

__turbopack_context__.n(__turbopack_context__.i("[project]/src/app/trahs/[trahId]/persons/[personId]/profile/page.tsx [app-rsc] (ecmascript)"));
}),
"[project]/src/auth.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

return __turbopack_context__.a(async (__turbopack_handle_async_dependencies__, __turbopack_async_result__) => { try {
__turbopack_context__.s([
    "auth",
    ()=>auth,
    "handlers",
    ()=>handlers,
    "signIn",
    ()=>signIn,
    "signOut",
    ()=>signOut
]);
// Auth.js (NextAuth v5) wiring for T-501.
//
// ADR-0004 calls for a Credentials provider with "database session
// strategy" backed by IAM's own users/sessions tables. Auth.js's own
// session-strategy option is more restrictive than that phrasing suggests:
// Auth.js explicitly REJECTS `session.strategy: "database"` when the only
// configured provider is Credentials (see
// node_modules/@auth/core/lib/utils/assert.js: "Signing in with
// credentials only supported if JWT strategy is enabled" /
// UnsupportedStrategy). Auth.js's built-in "database" strategy also
// assumes its own Adapter schema shape (Account/Session/User/
// VerificationToken with specific field names like `expires` rather than
// IAM's `expiresAt`), which doesn't match the schema IAM's contract
// functions already implement and fully own.
//
// Rather than fight that framework constraint or duplicate IAM's session
// logic behind a second, Adapter-shaped implementation, this config keeps
// Auth.js's *transport* (the signed cookie) on the JWT strategy, but
// treats IAM's own `sessionToken` (from login()/logout()/verifySession())
// as the actual source of truth for whether a session is valid:
//   - `authorize()` calls IAM's login(); on success, the sessionToken IAM
//     issued is embedded in the JWT payload (not a Auth.js-invented id).
//   - the `jwt` callback re-validates that sessionToken against the DB via
//     IAM's verifySession() on every subsequent request, so a session
//     revoked by logout() or confirmPasswordReset() (which deletes
//     Session rows) stops working immediately — genuine server-side
//     revocation, not just "valid until the JWT's own expiry."
//   - the `signOut` event calls IAM's logout() so the DB row is actually
//     removed, not just orphaned until it naturally expires.
//
// This satisfies the ADR's actual intent (revocable, DB-backed sessions
// reusing IAM's own tables/contract functions) within Auth.js's
// documented Credentials-provider constraint. Documented here since it's
// a deliberate deviation from the ADR's literal wording, not an oversight.
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2d$auth$2f$index$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__$3c$locals$3e$__ = __turbopack_context__.i("[project]/node_modules/next-auth/index.js [app-rsc] (ecmascript) <locals>");
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2d$auth$2f$providers$2f$credentials$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__$3c$locals$3e$__ = __turbopack_context__.i("[project]/node_modules/next-auth/providers/credentials.js [app-rsc] (ecmascript) <locals>");
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f40$auth$2f$core$2f$providers$2f$credentials$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/@auth/core/providers/credentials.js [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/lib/prisma.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$login$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/iam/login.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$logout$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/iam/logout.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$verifySession$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/iam/verifySession.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$rate$2d$limit$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/lib/rate-limit.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$client$2d$ip$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/lib/client-ip.ts [app-rsc] (ecmascript)");
var __turbopack_async_dependencies__ = __turbopack_handle_async_dependencies__([
    __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__
]);
[__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__] = __turbopack_async_dependencies__.then ? (await __turbopack_async_dependencies__)() : __turbopack_async_dependencies__;
;
;
;
;
;
;
;
;
function parseIdentifier(raw) {
    if (typeof raw !== "string" || raw.trim().length === 0) return null;
    const type = raw.includes("@") ? "EMAIL" : "PHONE";
    return {
        type,
        value: raw
    };
}
// Security fix (T-501 review, HIGH): login() had zero throttling —
// this is the primary, most-targeted entry point for credential-stuffing/
// password-brute-force bots, and login.ts's own timing-parity defense
// only prevents user-enumeration, not unlimited online guessing. Same
// class of protection as reset/confirm's limiter (see rate-limit.ts's
// doc comment for the accepted single-instance/V1 scope), a more
// generous window since legitimate users mistype passwords far more
// often than they need 6-digit codes.
const LOGIN_LIMIT = 10;
const LOGIN_WINDOW_MS = 15 * 60 * 1000; // 15 minutes
const loginLimiter = new __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$rate$2d$limit$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["FixedWindowRateLimiter"](LOGIN_LIMIT, LOGIN_WINDOW_MS);
const { handlers, auth, signIn, signOut } = (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$next$2d$auth$2f$index$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__$3c$locals$3e$__["default"])({
    session: {
        strategy: "jwt"
    },
    pages: {
        signIn: "/login"
    },
    providers: [
        (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f40$auth$2f$core$2f$providers$2f$credentials$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["default"])({
            credentials: {
                identifier: {
                    label: "Email or phone",
                    type: "text"
                },
                password: {
                    label: "Password",
                    type: "password"
                }
            },
            async authorize (credentials, request) {
                const identifier = parseIdentifier(credentials?.identifier);
                const password = typeof credentials?.password === "string" ? credentials.password : "";
                if (!identifier || !password) return null;
                // Rate-limit BEFORE calling login(), so a throttled attempt never
                // even reaches bcrypt.compare — keyed by identifier+IP, same
                // spirit as reset/confirm's limiter (identifier alone would let
                // one attacker lock out a victim; IP alone would let a botnet
                // spread guesses across addresses).
                const rateLimitKey = `${identifier.type}:${identifier.value.trim().toLowerCase()}|${(0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$client$2d$ip$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["clientIp"])(request)}`;
                const { allowed } = loginLimiter.check(rateLimitKey);
                if (!allowed) return null;
                const result = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$login$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["login"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], identifier, password);
                if (!result.ok) return null;
                // Everything after `id` is a custom field carried through to the
                // `jwt` callback's `user` argument on initial sign-in only.
                return {
                    id: result.userId,
                    sessionToken: result.sessionToken
                };
            }
        })
    ],
    callbacks: {
        async jwt ({ token, user }) {
            if (user) {
                // Initial sign-in: `user` is what authorize() returned above.
                token.sessionToken = user.sessionToken;
                token.userId = user.id;
                return token;
            }
            // Subsequent requests: re-check IAM's own session store so that
            // logout()/confirmPasswordReset() (both of which delete Session
            // rows) take effect immediately, not just once the JWT expires.
            if (typeof token.sessionToken === "string") {
                const userId = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$verifySession$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["verifySession"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], token.sessionToken);
                if (!userId) {
                    // Session was revoked server-side — strip credentials so the
                    // `session` callback below reports "signed out."
                    delete token.sessionToken;
                    delete token.userId;
                }
            }
            return token;
        },
        async session ({ session, token }) {
            if (typeof token.userId === "string") {
                session.user.id = token.userId;
            } else {
                // No valid IAM session behind this JWT (revoked or never set) —
                // surface as unauthenticated rather than a half-populated user.
                return {
                    ...session,
                    user: undefined,
                    expires: session.expires
                };
            }
            return session;
        }
    },
    events: {
        async signOut (message) {
            // With the "jwt" strategy, Auth.js's signOut event passes `{ token }`
            // rather than `{ session }`. Clean up the underlying IAM Session row
            // so it doesn't linger until its natural expiry.
            if ("token" in message && typeof message.token?.sessionToken === "string") {
                await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$logout$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["logout"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], message.token.sessionToken);
            }
        }
    }
});
__turbopack_async_result__();
} catch(e) { __turbopack_async_result__(e); } }, false);}),
"[project]/src/lib/client-ip.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// Shared client-IP extraction for rate-limiting purposes.
//
// Security fix (T-501 review, HIGH): a naive implementation that reads
// the FIRST entry of X-Forwarded-For is trivially spoofable — proxies
// (including Vercel) APPEND the real connecting client's address to the
// end of the list; the first entry is whatever the client itself sent in
// its own request and is fully attacker-controlled. Reading the LAST
// entry instead reflects the address the immediate, trusted proxy hop
// actually observed, which a client cannot forge (they can prepend fake
// entries, but not remove or rewrite the one their own connecting proxy
// appends).
//
// This is still not a perfect IP for a multi-hop/CDN setup (a compromised
// or misconfigured intermediate proxy could still lie), but it is not
// attacker-forgeable in the common single-reverse-proxy deployment this
// app targets (Vercel, per ADR-0003) the way "first entry" is.
__turbopack_context__.s([
    "clientIp",
    ()=>clientIp
]);
function clientIp(request) {
    const forwarded = request.headers.get("x-forwarded-for");
    if (!forwarded) return "unknown";
    const hops = forwarded.split(",").map((h)=>h.trim()).filter(Boolean);
    return hops.length > 0 ? hops[hops.length - 1] : "unknown";
}
}),
"[project]/src/lib/get-caller-membership.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

return __turbopack_context__.a(async (__turbopack_handle_async_dependencies__, __turbopack_async_result__) => { try {
__turbopack_context__.s([
    "getCallerMembership",
    ()=>getCallerMembership,
    "getCallerUserId",
    ()=>getCallerUserId
]);
// T-502 shared helper — resolves "the current session's userId, for a
// given trahId, to their membershipId" so every Route Handler under
// src/app/api/trahs/** (and later tickets that need the same pattern)
// does this exactly once, the same way.
//
// SECURITY: tier-a's changeRole/removeMember/invite contract functions
// take an `actingMembershipId` as an *input*, trusting the caller to have
// already verified it belongs to the authenticated user (see
// getMembership.ts's SECURITY NOTE — that lookup does no authorization of
// its own). This helper is the one place that trust boundary is enforced:
// it never accepts a client-supplied membershipId as "the actor" — it
// always derives it server-side from Auth.js's session + the trahId in
// the URL, via findMembershipByUserAndTrah's INV-TM-5-backed compound-key
// lookup (same discipline as getRole.ts). Route handlers should use this
// for the ACTOR only; a client-supplied membershipId may still be used as
// the TARGET of an action (e.g. which member to remove/change).
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$auth$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/auth.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/lib/prisma.ts [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$findMembershipByUserAndTrah$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/trah-membership/findMembershipByUserAndTrah.ts [app-rsc] (ecmascript)");
var __turbopack_async_dependencies__ = __turbopack_handle_async_dependencies__([
    __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$auth$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__,
    __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__
]);
[__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$auth$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__] = __turbopack_async_dependencies__.then ? (await __turbopack_async_dependencies__)() : __turbopack_async_dependencies__;
;
;
;
async function getCallerUserId() {
    const session = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$auth$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["auth"])();
    const userId = session?.user?.id;
    return typeof userId === "string" ? userId : null;
}
async function getCallerMembership(trahId) {
    const userId = await getCallerUserId();
    if (!userId) return null;
    const membership = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$findMembershipByUserAndTrah$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["findMembershipByUserAndTrah"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], trahId, userId);
    if (!membership || membership.status !== "ACTIVE") return null;
    return {
        userId,
        membershipId: membership.id
    };
}
__turbopack_async_result__();
} catch(e) { __turbopack_async_result__(e); } }, false);}),
"[project]/src/lib/prisma.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

return __turbopack_context__.a(async (__turbopack_handle_async_dependencies__, __turbopack_async_result__) => { try {
__turbopack_context__.s([
    "prisma",
    ()=>prisma
]);
// Standard Next.js + Prisma singleton pattern: in dev, Next.js hot-reloads
// modules on every file change, which would otherwise create a fresh
// PrismaClient (and a fresh DB connection pool) on every reload and
// eventually exhaust Postgres's connection limit. Stashing the instance on
// `globalThis` (which survives hot-reload, unlike module-local state)
// avoids that. In production there's only ever one module load, so this
// is a no-op there beyond the initial construction.
//
// Queries run through @prisma/adapter-pg (a plain-JS `pg` Pool) rather than
// Prisma's default Rust query engine — the Rust engine's Tokio runtime
// spawns one OS worker thread per reported CPU core, which exceeds the
// process/thread ceiling on constrained shared hosting and crashes with
// "OS can't spawn worker thread: Resource temporarily unavailable" on the
// very first request. The adapter has no native multi-threaded runtime.
var __TURBOPACK__imported__module__$5b$externals$5d2f40$prisma$2f$client__$5b$external$5d$__$2840$prisma$2f$client$2c$__cjs$2c$__$5b$project$5d2f$node_modules$2f40$prisma$2f$client$29$__ = __turbopack_context__.i("[externals]/@prisma/client [external] (@prisma/client, cjs, [project]/node_modules/@prisma/client)");
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f40$prisma$2f$adapter$2d$pg$2f$dist$2f$index$2e$mjs__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/@prisma/adapter-pg/dist/index.mjs [app-rsc] (ecmascript)");
var __turbopack_async_dependencies__ = __turbopack_handle_async_dependencies__([
    __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f40$prisma$2f$adapter$2d$pg$2f$dist$2f$index$2e$mjs__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__
]);
[__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f40$prisma$2f$adapter$2d$pg$2f$dist$2f$index$2e$mjs__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__] = __turbopack_async_dependencies__.then ? (await __turbopack_async_dependencies__)() : __turbopack_async_dependencies__;
;
;
const globalForPrisma = globalThis;
const adapter = new __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f40$prisma$2f$adapter$2d$pg$2f$dist$2f$index$2e$mjs__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["PrismaPg"]({
    connectionString: process.env.DATABASE_URL
});
const prisma = globalForPrisma.prisma ?? new __TURBOPACK__imported__module__$5b$externals$5d2f40$prisma$2f$client__$5b$external$5d$__$2840$prisma$2f$client$2c$__cjs$2c$__$5b$project$5d2f$node_modules$2f40$prisma$2f$client$29$__["PrismaClient"]({
    adapter
});
if ("TURBOPACK compile-time truthy", 1) {
    globalForPrisma.prisma = prisma;
}
__turbopack_async_result__();
} catch(e) { __turbopack_async_result__(e); } }, false);}),
"[project]/src/lib/rate-limit.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// Simple in-memory fixed-window rate limiter.
//
// Scope: V1-appropriate protection for a low-traffic single-instance app
// (per WORKPLAN.md's environment notes, this deploys to a small number of
// serverless instances, not a large fleet) — NOT a distributed limiter.
// It resets if the process restarts and does not coordinate across
// multiple server instances. That's an accepted tradeoff for V1: the
// spec's must-do is "have SOME rate limiting on reset/confirm, a handful
// of attempts per 15-minute window," not "build a production-grade
// distributed limiter." A Redis-backed limiter would be a natural
// follow-up if this app ever runs on more than one instance.
//
// Extracted as a pure class (no Next.js/Request coupling) so it's testable
// in isolation without spinning up a route handler.
__turbopack_context__.s([
    "FixedWindowRateLimiter",
    ()=>FixedWindowRateLimiter
]);
class FixedWindowRateLimiter {
    limit;
    windowMs;
    hits;
    constructor(limit, windowMs){
        this.limit = limit;
        this.windowMs = windowMs;
        this.hits = new Map();
    }
    /**
   * Records an attempt for `key` and reports whether it's allowed under the
   * limit. Pass `now` explicitly in tests to control window boundaries.
   */ check(key, now = Date.now()) {
        const existing = this.hits.get(key);
        if (!existing || now - existing.windowStart >= this.windowMs) {
            // New window (first attempt ever for this key, or the previous
            // window has fully elapsed).
            this.hits.set(key, {
                count: 1,
                windowStart: now
            });
            return {
                allowed: true,
                remaining: this.limit - 1
            };
        }
        if (existing.count >= this.limit) {
            return {
                allowed: false,
                remaining: 0
            };
        }
        existing.count += 1;
        return {
            allowed: true,
            remaining: this.limit - existing.count
        };
    }
    /** Test/diagnostic helper — not used by route handlers. */ reset() {
        this.hits.clear();
    }
}
}),
"[project]/src/modules/genealogy/getProfile.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-305 (standard lane) — Genealogy getProfile() contract function.
// See spec/genealogy/tier-a-contract.md:
//   getProfile(trahId, personId, viewerMembershipId?: MembershipId | null)
//     -> ProfileView | null
//   // viewerMembershipId may be null for a PUBLIC, unauthenticated view
//   // (only PUBLIC-visibility fields are returned in that case).
// and spec/genealogy/tier-b-implementation.md's "Contact privacy
// resolution (REQ-ID-004, REQ-PRIV-001/002)" table plus its closing
// paragraph:
//   "`getProfile` with `viewerMembershipId = null`... returns only
//    `PUBLIC`-visibility Contacts and whatever identity fields the Trah
//    has not restricted below `PUBLIC` — V1 default is that unauthenticated
//    access returns identity summary only (name, life status) with no
//    Contact fields unless explicitly `PUBLIC`."
//
// No FORBIDDEN branch: unlike getTree/searchByName, tier-a's getProfile
// signature already models the "no permission" case correctly as data — a
// null/inactive/wrong-Trah viewer is not an error, it is the documented
// PUBLIC-visitor path (REQ-ID-004's own acceptance case). This is NOT the
// same gap T-304 fixed on findRelationship (where an unauthorized ask was
// indistinguishable from the legitimate answer "UNRELATED"); here "public
// view, PUBLIC fields only" is itself a legitimate, distinct answer, so no
// contract revision is needed for this function.
//
// --- Judgment calls (flagged for reviewer) --------------------------------
//
// 1. person_facts / residences visibility: tier-b's privacy table only
//    covers Contacts explicitly, plus one aside that identity/date/place
//    facts default to FAMILY-visible for a DECEASED person and that
//    unauthenticated access gets "identity summary only (name, life
//    status)... no Contact fields unless explicitly PUBLIC." Read together,
//    this implementation treats ALL `person_facts` (regardless of the
//    Person's life_status) and ALL `residences` as FAMILY-visible-only —
//    returned only to an ACTIVE Membership in trahId, never to a null/
//    inactive/wrong-Trah viewer. Residences have no visibility column at
//    all in the schema, so there's no per-row distinction to make; FAMILY-
//    only is the closest reading of "identity summary only" for public
//    access. Flagged as an extrapolation, not a literal reading of a table
//    that only lists Contact rows.
//
// 2. Relationship graph (parents/partners/children/siblings) visibility:
//    not addressed by tier-b's privacy section at all. Treated the same as
//    facts/residences above (FAMILY-only) for consistency — an
//    unauthenticated visitor gets identity + PUBLIC contacts only, no
//    family-graph data. Flagged as an extrapolation.
//
// 3. `ONLY_ME` contact visibility ("only the User whose claimed Person...
//    equals this profile's Person", per tier-b's table, via
//    `TrahMembership.isPersonClaimed`): `isPersonClaimed` does not exist
//    as a Trah & Membership contract function yet (checked
//    src/modules/trah-membership/ — no such file). However,
//    `getMembership()`'s own return type already exposes
//    `claimedPersonId` directly on the viewer's own membership record, and
//    a self-only check ("does the ASKING viewer's own claimed Person match
//    THIS profile's Person") needs exactly that one piece of data, not a
//    reverse lookup across all memberships. This is used here instead of
//    a missing `isPersonClaimed` call — it answers the same question this
//    one check needs, using only the already-contracted `getMembership`
//    return shape. What genuinely cannot be built without `isPersonClaimed`
//    (a claim BADGE — "has ANY user claimed this Person," independent of
//    who's asking, REQ-PROF-002) is left out of ProfileView entirely,
//    documented as a deferred gap, same pattern as Audit-not-wired-yet
//    elsewhere in this module.
//
// 4. `createPerson`'s known displayName/person_facts sync gap (WORKPLAN.md
//    "Known gaps before real users") means a profile's `displayName` field
//    (read from the denormalized `Person.displayName` column, same source
//    tier-b names for `searchByName`) may not reflect a later-corrected
//    FULL_NAME fact — inherited, not introduced by this ticket; see
//    searchByName.ts's header for the same note.
__turbopack_context__.s([
    "getProfile",
    ()=>getProfile
]);
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$getMembership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/trah-membership/getMembership.ts [app-rsc] (ecmascript)");
;
async function getProfile(prisma, trahId, personId, viewerMembershipId) {
    const person = await prisma.person.findUnique({
        where: {
            id: personId
        }
    });
    if (!person || person.trahId !== trahId) {
        return null;
    }
    const membership = viewerMembershipId ? await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$getMembership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["getMembership"])(prisma, viewerMembershipId) : null;
    const isActiveMember = !!membership && membership.trahId === trahId && membership.status === "ACTIVE";
    const isOwnClaimedPerson = isActiveMember && membership.claimedPersonId === personId;
    const [facts, residences, contacts, relationships] = await Promise.all([
        isActiveMember ? prisma.personFact.findMany({
            where: {
                personId
            }
        }) : Promise.resolve([]),
        isActiveMember ? prisma.residence.findMany({
            where: {
                personId
            }
        }) : Promise.resolve([]),
        prisma.contact.findMany({
            where: {
                personId
            }
        }),
        isActiveMember ? prisma.relationship.findMany({
            where: {
                trahId,
                OR: [
                    {
                        personAId: personId
                    },
                    {
                        personBId: personId
                    }
                ]
            }
        }) : Promise.resolve([])
    ]);
    const factViews = facts.map((f)=>({
            id: f.id,
            field: f.field,
            value: f.value,
            precisionQualifier: f.precisionQualifier ?? null,
            verificationStatus: f.verificationStatus,
            source: f.source ?? null,
            isPreferred: f.isPreferred
        }));
    const residenceViews = residences.map((r)=>({
            id: r.id,
            place: r.place,
            startDate: r.startDate,
            endDate: r.endDate ?? null,
            isCurrent: r.isCurrent
        }));
    // Contact visibility resolution (REQ-PRIV-001/002 table): PUBLIC always
    // visible; FAMILY visible to any ACTIVE member of trahId; ONLY_ME visible
    // only to the viewer whose own claimed Person is this profile's Person
    // (see judgment call #3 above).
    const contactViews = contacts.filter((c)=>{
        if (c.visibility === "PUBLIC") return true;
        if (c.visibility === "FAMILY") return isActiveMember;
        if (c.visibility === "ONLY_ME") return isOwnClaimedPerson;
        return false;
    }).map((c)=>({
            id: c.id,
            type: c.type,
            value: c.value,
            visibility: c.visibility
        }));
    const parents = [];
    const partners = [];
    const children = [];
    const siblings = [];
    if (relationships.length > 0) {
        const otherPersonIds = new Set();
        for (const r of relationships){
            const otherId = r.personAId === personId ? r.personBId : r.personAId;
            otherPersonIds.add(otherId);
        }
        const otherPersons = await prisma.person.findMany({
            where: {
                id: {
                    in: [
                        ...otherPersonIds
                    ]
                }
            }
        });
        const otherPersonMap = new Map(otherPersons.map((p)=>[
                p.id,
                {
                    id: p.id,
                    displayName: p.displayName
                }
            ]));
        const toSummary = (id)=>otherPersonMap.get(id) ?? {
                id,
                displayName: id
            };
        for (const r of relationships){
            if (r.type === "PARTNER") {
                const otherId = r.personAId === personId ? r.personBId : r.personAId;
                partners.push(toSummary(otherId));
            } else if (r.type === "SIBLING") {
                const otherId = r.personAId === personId ? r.personBId : r.personAId;
                siblings.push(toSummary(otherId));
            } else {
                // *_PARENT_CHILD: personAId = parent, personBId = child.
                if (r.personBId === personId) {
                    parents.push(toSummary(r.personAId));
                } else if (r.personAId === personId) {
                    children.push(toSummary(r.personBId));
                }
            }
        }
    }
    return {
        id: person.id,
        trahId: person.trahId,
        displayName: person.displayName,
        gender: isActiveMember ? person.gender : null,
        lifeStatus: person.lifeStatus,
        facts: factViews,
        residences: residenceViews,
        contacts: contactViews,
        parents,
        partners,
        children,
        siblings
    };
}
}),
"[project]/src/modules/iam/identifier.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// Shared identifier type + normalization for IAM's email-or-phone login
// scheme. Extracted so register.ts and login.ts can't silently drift
// (review follow-up from T-102).
__turbopack_context__.s([
    "normalizeIdentifier",
    ()=>normalizeIdentifier
]);
function normalizeIdentifier(identifier) {
    const trimmed = identifier.value.trim();
    return identifier.type === "EMAIL" ? trimmed.toLowerCase() : trimmed;
}
}),
"[project]/src/modules/iam/login.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

__turbopack_context__.s([
    "login",
    ()=>login
]);
// T-102 — IAM login() contract function.
// See spec/iam/tier-a-contract.md (signature, INV-IAM-4) and
// spec/iam/tier-b-implementation.md (schema, session expiry, "same generic
// error for unknown identifier vs wrong password" edge case).
var __TURBOPACK__imported__module__$5b$externals$5d2f$crypto__$5b$external$5d$__$28$crypto$2c$__cjs$29$__ = __turbopack_context__.i("[externals]/crypto [external] (crypto, cjs)");
var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$bcryptjs$2f$index$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/bcryptjs/index.js [app-rsc] (ecmascript)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$identifier$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/iam/identifier.ts [app-rsc] (ecmascript)");
;
;
;
const SESSION_LIFETIME_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
const SESSION_TOKEN_BYTES = 32; // 32 bytes -> 64 hex chars, well over the 32-char floor
// Dummy hash to compare against when the identifier doesn't match a User,
// so a failed lookup still pays the bcrypt.compare cost — mitigates
// timing-based user enumeration (same code path either way).
const DUMMY_HASH_FOR_TIMING_PARITY = "$2a$10$CwTycUXWue0Thq9StjUM0uJ8i1Ax/OhpFrOTdmKGKQ8pC/S8v7B9m";
async function login(prisma, identifier, password) {
    const value = (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$iam$2f$identifier$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["normalizeIdentifier"])(identifier);
    // Same field-scoped lookup pattern as register.ts: email checked
    // against email, phone against phone — never a combined OR.
    const user = identifier.type === "EMAIL" ? await prisma.user.findFirst({
        where: {
            email: value
        }
    }) : await prisma.user.findFirst({
        where: {
            phone: value
        }
    });
    const passwordMatches = await __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$bcryptjs$2f$index$2e$js__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["default"].compare(password, user?.passwordHash ?? DUMMY_HASH_FOR_TIMING_PARITY);
    if (!user || !passwordMatches) {
        return {
            ok: false,
            error: "INVALID_CREDENTIALS"
        };
    }
    const sessionToken = __TURBOPACK__imported__module__$5b$externals$5d2f$crypto__$5b$external$5d$__$28$crypto$2c$__cjs$29$__["default"].randomBytes(SESSION_TOKEN_BYTES).toString("hex");
    const expiresAt = new Date(Date.now() + SESSION_LIFETIME_MS);
    await prisma.session.create({
        data: {
            sessionToken,
            userId: user.id,
            expiresAt
        }
    });
    return {
        ok: true,
        sessionToken,
        userId: user.id
    };
}
}),
"[project]/src/modules/iam/logout.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-102 — IAM logout() contract function.
// See spec/iam/tier-a-contract.md (signature, INV-IAM-4).
__turbopack_context__.s([
    "logout",
    ()=>logout
]);
async function logout(prisma, sessionToken) {
    // Judgment call (Tier B doesn't specify delete vs. expire-flag): delete
    // the row — simplest reading that satisfies INV-IAM-4 (a subsequent
    // verifySession lookup finds nothing).
    await prisma.session.deleteMany({
        where: {
            sessionToken
        }
    });
}
}),
"[project]/src/modules/iam/verifySession.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-102 — IAM verifySession() contract function.
// See spec/iam/tier-a-contract.md (signature, INV-IAM-4) and
// spec/iam/tier-b-implementation.md (session expiry logic — expired
// sessions must be treated as invalid, same as nonexistent).
__turbopack_context__.s([
    "verifySession",
    ()=>verifySession
]);
async function verifySession(prisma, sessionToken) {
    const session = await prisma.session.findUnique({
        where: {
            sessionToken
        }
    });
    if (!session) return null;
    if (session.expiresAt.getTime() <= Date.now()) return null;
    return session.userId;
}
}),
"[project]/src/modules/trah-membership/canWrite.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-203 (danger-list: auth-RBAC) — canWrite() permission check.
// See spec/trah-membership/tier-a-contract.md:
//   canWrite(membershipId: MembershipId) -> boolean
//     // true iff role in { OWNER, ADMIN, EDITOR } and status = ACTIVE
//
// Reuses getMembership's by-id lookup (same query shape); no auth check of
// its own beyond the given membership's own role/status — caller is
// responsible for supplying a membershipId that belongs to the acting user.
__turbopack_context__.s([
    "canWrite",
    ()=>canWrite
]);
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$getMembership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/trah-membership/getMembership.ts [app-rsc] (ecmascript)");
;
const WRITE_ROLES = new Set([
    "OWNER",
    "ADMIN",
    "EDITOR"
]);
async function canWrite(prisma, membershipId) {
    const membership = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$trah$2d$membership$2f$getMembership$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["getMembership"])(prisma, membershipId);
    if (!membership) return false;
    return membership.status === "ACTIVE" && WRITE_ROLES.has(membership.role);
}
}),
"[project]/src/modules/trah-membership/findMembershipByUserAndTrah.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-201 (danger-list: auth-RBAC) — internal read helper, NOT a
// tier-a-contract.md function by this name. tier-a's `getMembership` is a
// lookup BY membershipId (see getMembership.ts); this helper resolves the
// (trahId, userId) pair callers actually have at request time (e.g. a
// route handler with a session userId and a Trah id from the URL) into a
// Membership row, INV-TM-5's one-per-(user,trah) key. Used internally by
// this module (and by getRole.ts) — not a cross-module contract call.
//
// See spec/trah-membership/tier-b-implementation.md (`memberships` schema,
// `@@unique([trahId, userId])`) and REQ-FAM-005 / INV-TM-6 (every read
// scoped by trahId AND userId, never userId alone).
__turbopack_context__.s([
    "findMembershipByUserAndTrah",
    ()=>findMembershipByUserAndTrah
]);
async function findMembershipByUserAndTrah(prisma, trahId, userId) {
    // INV-TM-5's `@@unique([trahId, userId])` compound key backs this
    // lookup — findUnique against the (unnamed, Prisma-default-named)
    // `trahId_userId` compound key.
    return prisma.membership.findUnique({
        where: {
            trahId_userId: {
                trahId,
                userId
            }
        }
    });
}
}),
"[project]/src/modules/trah-membership/getMembership.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-201 (danger-list: auth-RBAC) — getMembership() contract function.
// See spec/trah-membership/tier-a-contract.md:
//   getMembership(membershipId: MembershipId) -> MembershipView | null
//   MembershipView = { id, trahId, userId, role, claimedPersonId, status }
// Lookup BY membership id (not by trahId/userId — see
// findMembershipByUserAndTrah.ts for that shape).
//
// SECURITY NOTE (T-201 review, must read before adding any caller): this
// function performs NO authorization check of its own — it returns
// whatever membership matches the given id, including another Trah's
// data, regardless of who's asking. That's intentional per tier-a (a raw
// lookup primitive), but it means every future caller (e.g. Audit's
// getHistory, or any route handler) MUST independently verify the
// CALLING user's own membership/session is authorized for the target
// Trah before trusting this result. Never expose membershipId as a raw,
// unauthenticated route parameter that calls straight into this
// function — that would be a horizontal privilege-escalation bug
// (enumerate membershipId, read another Trah's userId/role/claimedPersonId).
__turbopack_context__.s([
    "getMembership",
    ()=>getMembership
]);
async function getMembership(prisma, membershipId) {
    const membership = await prisma.membership.findUnique({
        where: {
            id: membershipId
        }
    });
    if (!membership) return null;
    return {
        id: membership.id,
        trahId: membership.trahId,
        userId: membership.userId,
        role: membership.role,
        claimedPersonId: membership.claimedPersonId,
        status: membership.status
    };
}
}),
"[project]/src/modules/trah-membership/isPersonClaimed.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-204 (danger-list: auth-RBAC) — isPersonClaimed() contract function.
//
// See spec/trah-membership/tier-a-contract.md:
//   isPersonClaimed(trahId: TrahId, personId: PersonId)
//     -> { claimed: boolean, byUserId?: UserId }
//
// INV-TM-6: every read scoped by trahId/userId — this must never return a
// claim result for a Person outside the given trahId (must behave as
// "not claimed" / not found for cross-Trah personId, never leak whether
// the personId exists in a different Trah).
//
// Query shape (house convention): find an ACTIVE Membership whose
// claimedPersonId === personId AND whose trahId === trahId (both
// conditions in the same where-clause, not personId alone — a claim by a
// REMOVED membership must not count, and a personId belonging to a
// different trahId must not match even if by coincidence a Membership
// elsewhere claims a same-valued id).
__turbopack_context__.s([
    "isPersonClaimed",
    ()=>isPersonClaimed
]);
async function isPersonClaimed(prisma, trahId, personId) {
    const claimer = await prisma.membership.findFirst({
        where: {
            trahId,
            claimedPersonId: personId,
            status: "ACTIVE"
        }
    });
    if (!claimer) {
        return {
            claimed: false
        };
    }
    return {
        claimed: true,
        byUserId: claimer.userId
    };
}
}),
];

//# sourceMappingURL=%5Broot-of-the-server%5D__0yuf72t._.js.map