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]/tree/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",
    ()=>FamilyTreePage
]);
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)");
// Interactive family tree page (T-506). REQ-TREE-001..003.
//
// Server Component: resolves the caller's own Membership for this trahId
// via getCallerMembership (same discipline as every other page under
// src/app/trahs/[trahId]/**), then calls genealogy's getTree() DIRECTLY
// (not via the /api/trahs/[trahId]/tree Route Handler — that route exists
// for programmatic/future client-fetch use, but a Server Component calling
// the same contract function in-process avoids a redundant self-fetch,
// same as edit/page.tsx querying Prisma directly rather than hitting its
// own API routes).
//
// --- Judgment calls (flagged for reviewer) --------------------------------
//
// 1. Default root: the ticket allows "a simple way to get a default root".
//    When `?root=` is absent, this page picks the Trah's earliest-created
//    Person (a direct Prisma query, read-only, scoped by trahId) as the
//    default root. If the Trah has zero Persons yet, it shows an empty
//    state linking to the "add person" flow instead of calling getTree.
//
// 2. Expand/collapse (REQ-TREE-001/002's "expand/collapse" + "center on
//    person" asks): implemented as ONE mechanism, not two. Every person
//    node rendered in the tree (ancestor, root, or descendant) is a link
//    that re-navigates to `?root=[personId]&depth=[currentDepth]`. This
//    both re-centers the tree on that person AND, because getTree()
//    re-traverses fresh from the new root out to `depth` generations in
//    every direction, effectively "expands" whatever was previously a
//    depth-boundary leaf (its own ancestors/descendants beyond the old
//    root's cutoff now load). There's no separate client-side collapse
//    animation/state — server-driven re-fetch-on-click, per the ticket's
//    stated acceptable V1 interpretation. This keeps the whole page a pure
//    Server Component (no client JS needed at all for navigation).
//
// 3. Depth control: four preset links (2/3/5/10 generations each
//    direction) rather than a slider or raw number input — getTree's
//    depth is clamped server-side to [1, 10] by the Route Handler; other
//    values (1, 4, 6-9) are reachable by hand-editing the URL but have no
//    dedicated UI control, an accepted V1 simplification (T-506 review).
//
// 4. Multi-partner separation (REQ-TREE-003, acceptance-critical): each
//    PartnerBranch renders as its own bordered <section> with the partner's
//    name (or "no partner on record") as a sub-heading, so a person with
//    children by 2+ partners shows 2+ visually distinct boxes rather than
//    one merged children list. See <PartnerBranches> below.
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$genealogy$2f$getTree$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/genealogy/getTree.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__;
;
;
;
;
;
;
const DEFAULT_DEPTH = 3;
const DEPTH_PRESETS = [
    2,
    3,
    5,
    10
];
function parseDepth(raw) {
    if (!raw) return DEFAULT_DEPTH;
    const parsed = Number.parseInt(raw, 10);
    if (!Number.isFinite(parsed)) return DEFAULT_DEPTH;
    return Math.min(10, Math.max(1, parsed));
}
function subtypeLabel(subtype) {
    switch(subtype){
        case "BIOLOGICAL_PARENT_CHILD":
            return "biological";
        case "ADOPTIVE_PARENT_CHILD":
            return "adoptive";
        case "STEP_PARENT_CHILD":
            return "step";
        default:
            return subtype;
    }
}
function treeUrl(trahId, rootPersonId, depth) {
    return `/trahs/${trahId}/tree?root=${encodeURIComponent(rootPersonId)}&depth=${depth}`;
}
function PersonLink({ trahId, person, depth, isRoot }) {
    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"])(__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: treeUrl(trahId, person.id, depth),
        style: {
            fontWeight: isRoot ? 700 : 500,
            textDecoration: "none",
            color: isRoot ? "#111" : "#0b5",
            border: isRoot ? "2px solid #111" : "1px solid #ccc",
            borderRadius: 6,
            padding: "0.15rem 0.5rem",
            display: "inline-block",
            background: isRoot ? "#f6f6f6" : "#fff"
        },
        title: "Click to re-center the tree on this person",
        children: person.displayName
    }, void 0, false, {
        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
        lineNumber: 95,
        columnNumber: 5
    }, this);
}
// Ancestors going up: a node's OWN parents (further generations up) render
// ABOVE the node itself in document order, so the whole ancestor side reads
// oldest-generation-first at the top, root at the bottom.
function AncestorList({ trahId, nodes, depth }) {
    if (nodes.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"])("ul", {
        style: {
            listStyle: "none",
            margin: 0,
            padding: 0,
            display: "flex",
            gap: "1rem"
        },
        children: nodes.map((node)=>/*#__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", {
                style: {
                    display: "flex",
                    flexDirection: "column",
                    alignItems: "center",
                    gap: "0.4rem"
                },
                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"])(AncestorList, {
                        trahId: trahId,
                        nodes: node.parents,
                        depth: depth
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 134,
                        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"])("div", {
                        style: {
                            fontSize: "0.75rem",
                            color: "#888"
                        },
                        children: [
                            "gen -",
                            node.generation,
                            " (",
                            subtypeLabel(node.subtype),
                            ")"
                        ]
                    }, void 0, true, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 135,
                        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"])(PersonLink, {
                        trahId: trahId,
                        person: node.person,
                        depth: depth
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 138,
                        columnNumber: 11
                    }, this)
                ]
            }, `${node.person.id}-${node.generation}`, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 130,
                columnNumber: 9
            }, this))
    }, void 0, false, {
        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
        lineNumber: 128,
        columnNumber: 5
    }, this);
}
// REQ-TREE-003: each PartnerBranch is its own bordered box so 2+ partners
// with children never visually merge into one list.
function PartnerBranches({ trahId, branches, depth }) {
    if (branches.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"])("div", {
        style: {
            display: "flex",
            flexDirection: "column",
            gap: "0.75rem",
            marginTop: "0.5rem"
        },
        children: branches.map((branch, index)=>/*#__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", {
                style: {
                    border: "1px solid #ddd",
                    borderRadius: 8,
                    padding: "0.5rem 0.75rem",
                    background: "#fafafa"
                },
                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"])("div", {
                        style: {
                            fontSize: "0.8rem",
                            color: "#555",
                            marginBottom: "0.4rem"
                        },
                        children: branch.partner ? /*#__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: [
                                "with ",
                                /*#__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"])(PersonLink, {
                                    trahId: trahId,
                                    person: branch.partner,
                                    depth: depth
                                }, void 0, false, {
                                    fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                                    lineNumber: 172,
                                    columnNumber: 22
                                }, this),
                                branch.partnerStatus ? ` (${branch.partnerStatus})` : ""
                            ]
                        }, void 0, true, {
                            fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                            lineNumber: 171,
                            columnNumber: 15
                        }, this) : "no partner on record for these children"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 169,
                        columnNumber: 11
                    }, this),
                    branch.children.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", {
                        style: {
                            margin: 0,
                            fontSize: "0.8rem",
                            color: "#999"
                        },
                        children: "No children recorded."
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 180,
                        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"])("ul", {
                        style: {
                            listStyle: "none",
                            margin: 0,
                            padding: 0,
                            display: "flex",
                            gap: "1rem",
                            flexWrap: "wrap"
                        },
                        children: branch.children.map((child)=>/*#__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"])(DescendantItem, {
                                trahId: trahId,
                                node: child,
                                depth: depth
                            }, child.person.id, false, {
                                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                                lineNumber: 184,
                                columnNumber: 17
                            }, this))
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 182,
                        columnNumber: 13
                    }, this)
                ]
            }, branch.partnerId ?? `no-partner-${index}`, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 160,
                columnNumber: 9
            }, this))
    }, void 0, false, {
        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
        lineNumber: 158,
        columnNumber: 5
    }, this);
}
function DescendantItem({ trahId, node, depth }) {
    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"])("li", {
        style: {
            display: "flex",
            flexDirection: "column",
            alignItems: "flex-start",
            gap: "0.25rem"
        },
        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"])("div", {
                style: {
                    fontSize: "0.75rem",
                    color: "#888"
                },
                children: [
                    "gen +",
                    node.generation,
                    " (",
                    subtypeLabel(node.subtype),
                    ")"
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 205,
                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"])(PersonLink, {
                trahId: trahId,
                person: node.person,
                depth: depth
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 208,
                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"])(PartnerBranches, {
                trahId: trahId,
                branches: node.partnerBranches,
                depth: depth
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 209,
                columnNumber: 7
            }, this)
        ]
    }, void 0, true, {
        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
        lineNumber: 204,
        columnNumber: 5
    }, this);
}
function DepthControl({ trahId, rootPersonId, depth }) {
    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"])("div", {
        style: {
            display: "flex",
            gap: "0.5rem",
            alignItems: "center",
            marginBottom: "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"])("span", {
                style: {
                    fontSize: "0.85rem",
                    color: "#555"
                },
                children: "Generations:"
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 225,
                columnNumber: 7
            }, this),
            DEPTH_PRESETS.map((preset)=>/*#__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: treeUrl(trahId, rootPersonId, preset),
                    style: {
                        fontSize: "0.85rem",
                        padding: "0.15rem 0.5rem",
                        border: preset === depth ? "1px solid #111" : "1px solid #ccc",
                        fontWeight: preset === depth ? 700 : 400,
                        borderRadius: 4,
                        textDecoration: "none",
                        color: "#333"
                    },
                    children: preset === 10 ? "10 (max)" : preset
                }, preset, false, {
                    fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                    lineNumber: 227,
                    columnNumber: 9
                }, this))
        ]
    }, void 0, true, {
        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
        lineNumber: 224,
        columnNumber: 5
    }, this);
}
async function FamilyTreePage({ params, searchParams }) {
    const { trahId } = await params;
    const { root, depth: depthParam } = await searchParams;
    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);
    if (!caller) {
        (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$__["redirect"])("/login");
    }
    const trah = await __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"].trah.findUnique({
        where: {
            id: trahId
        }
    });
    if (!trah) {
        (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 depth = parseDepth(depthParam);
    let rootPersonId = root?.trim();
    if (!rootPersonId) {
        const defaultPerson = await __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"].person.findFirst({
            where: {
                trahId
            },
            orderBy: {
                createdAt: "asc"
            }
        });
        rootPersonId = defaultPerson?.id;
    }
    if (!rootPersonId) {
        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: [
                        "Family tree: ",
                        trah.name
                    ]
                }, void 0, true, {
                    fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                    lineNumber: 281,
                    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: "No persons recorded yet in this Trah."
                }, void 0, false, {
                    fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                    lineNumber: 282,
                    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"])(__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/new`,
                    children: "Add the first person"
                }, void 0, false, {
                    fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                    lineNumber: 283,
                    columnNumber: 9
                }, this)
            ]
        }, void 0, true, {
            fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
            lineNumber: 280,
            columnNumber: 7
        }, this);
    }
    const result = await (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$genealogy$2f$getTree$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["getTree"])(__TURBOPACK__imported__module__$5b$project$5d2f$src$2f$lib$2f$prisma$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["prisma"], trahId, rootPersonId, depth, caller.membershipId);
    if (!result.ok) {
        // caller is already known to be an ACTIVE member of trahId (via
        // getCallerMembership above), so getTree's FORBIDDEN branch shouldn't
        // be reachable here in practice — treated as a 404 rather than leaking
        // an unhandled 500.
        (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 { tree } = result;
    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: 960,
            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: [
                    "Family tree: ",
                    trah.name
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 301,
                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", {
                style: {
                    fontSize: "0.85rem",
                    color: "#666"
                },
                children: [
                    "Centered on ",
                    /*#__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: tree.root.displayName
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 303,
                        columnNumber: 21
                    }, this),
                    ". Click any person to re-center the tree on them."
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 302,
                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"])(DepthControl, {
                trahId: trahId,
                rootPersonId: rootPersonId,
                depth: depth
            }, void 0, false, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 307,
                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", {
                style: {
                    marginBottom: "1.5rem"
                },
                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", {
                        style: {
                            fontSize: "1rem"
                        },
                        children: "Ancestors"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 310,
                        columnNumber: 9
                    }, this),
                    tree.ancestors.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", {
                        style: {
                            fontSize: "0.85rem",
                            color: "#999"
                        },
                        children: "No ancestors recorded."
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 312,
                        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"])(AncestorList, {
                        trahId: trahId,
                        nodes: tree.ancestors,
                        depth: depth
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 314,
                        columnNumber: 11
                    }, this)
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 309,
                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", {
                style: {
                    margin: "1.5rem 0",
                    textAlign: "center"
                },
                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"])("div", {
                        style: {
                            fontSize: "0.75rem",
                            color: "#888"
                        },
                        children: "root"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 319,
                        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"])(PersonLink, {
                        trahId: trahId,
                        person: tree.root,
                        depth: depth,
                        isRoot: true
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 320,
                        columnNumber: 9
                    }, this)
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 318,
                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", {
                        style: {
                            fontSize: "1rem"
                        },
                        children: "Descendants"
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 324,
                        columnNumber: 9
                    }, this),
                    tree.descendants.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", {
                        style: {
                            fontSize: "0.85rem",
                            color: "#999"
                        },
                        children: "No descendants recorded."
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 326,
                        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"])(PartnerBranches, {
                        trahId: trahId,
                        branches: tree.descendants,
                        depth: depth
                    }, void 0, false, {
                        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                        lineNumber: 328,
                        columnNumber: 11
                    }, this)
                ]
            }, void 0, true, {
                fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
                lineNumber: 323,
                columnNumber: 7
            }, this)
        ]
    }, void 0, true, {
        fileName: "[project]/src/app/trahs/[trahId]/tree/page.tsx",
        lineNumber: 300,
        columnNumber: 5
    }, this);
}
__turbopack_async_result__();
} catch(e) { __turbopack_async_result__(e); } }, false);}),
"[project]/src/app/trahs/[trahId]/tree/page.tsx [app-rsc] (ecmascript, Next.js Server Component)", (function(__turbopack_context__){

__turbopack_context__.n(__turbopack_context__.i("[project]/src/app/trahs/[trahId]/tree/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/getTree.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-305 (standard lane) — Genealogy getTree() contract function.
// See spec/genealogy/tier-a-contract.md:
//   getTree(trahId, rootPersonId, depth, viewerMembershipId)
//     -> Result<TreeGraph, "FORBIDDEN">
// and spec/genealogy/tier-b-implementation.md's
// "`getTree(trahId, rootPersonId, depth)` reuses parentsOf/childrenOf...
// plus partnersOf per node" + REQ-TREE-001..003.
//
// Contract-gap fix (same pattern as T-304's findRelationship fix): tier-a's
// signature for getTree had no error branch at all (plain `-> TreeGraph`),
// even though tier-b explicitly requires the same "ACTIVE Membership in
// trahId" read-permission check as searchByName/findRelationship ("REQ-TREE
// reuses..." + tier-b's Search section's stated requirement, applied
// identically here since getTree has the same Trah-boundary read-permission
// need per INV-GEN-7). tier-a-contract.md is revised as part of T-305 to
// `Result<TreeGraph, "FORBIDDEN">`, following the T-304 precedent exactly
// (typed error instead of throwing, so an unauthorized/wrong-Trah caller
// gets a distinguishable result rather than a thrown exception or a
// misleadingly "empty" tree).
//
// This is the DB-touching wrapper only: check the viewer's read
// permission, load the Trah's Relationship + Person rows (scoped by
// trahId, INV-GEN-7), then delegate to the pure computeTree() in tree.ts
// (unit-tested independently there, per tier-a's "Isolation / testability
// note").
__turbopack_context__.s([
    "getTree",
    ()=>getTree
]);
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)");
var __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$genealogy$2f$tree$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/src/modules/genealogy/tree.ts [app-rsc] (ecmascript)");
;
;
async function getTree(prisma, trahId, rootPersonId, depth, viewerMembershipId) {
    // Read-permission check: viewer must be an ACTIVE member of this trahId
    // (mirrors findRelationship.ts / searchByName's stated requirement).
    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, viewerMembershipId);
    if (!membership || membership.trahId !== trahId || membership.status !== "ACTIVE") {
        return {
            ok: false,
            error: "FORBIDDEN"
        };
    }
    const [relationships, persons] = await Promise.all([
        prisma.relationship.findMany({
            where: {
                trahId
            }
        }),
        prisma.person.findMany({
            where: {
                trahId
            }
        })
    ]);
    const edges = relationships.map((r)=>({
            relationshipId: r.id,
            personAId: r.personAId,
            personBId: r.personBId,
            type: r.type,
            partnerStatus: r.partnerStatus
        }));
    const personSummaries = persons.map((p)=>({
            id: p.id,
            displayName: p.displayName
        }));
    const tree = (0, __TURBOPACK__imported__module__$5b$project$5d2f$src$2f$modules$2f$genealogy$2f$tree$2e$ts__$5b$app$2d$rsc$5d$__$28$ecmascript$29$__["computeTree"])(edges, personSummaries, rootPersonId, depth);
    return {
        ok: true,
        tree
    };
}
}),
"[project]/src/modules/genealogy/tree.ts [app-rsc] (ecmascript)", ((__turbopack_context__) => {
"use strict";

// T-305 (standard lane) — pure tree-traversal algorithm for getTree().
// See spec/genealogy/tier-a-contract.md's getTree entry and
// spec/genealogy/tier-b-implementation.md's:
//   "`getTree(trahId, rootPersonId, depth)` reuses `parentsOf`/`childrenOf`
//    (BFS both directions up to `depth`) plus `partnersOf` per node.
//    **REQ-TREE-003** (children grouped correctly under the right partner
//    pairing): for a Person with children by more than one partner, each
//    child is grouped under the `PARTNER` relationship id connecting its
//    two parents, if one exists; if the two parents have no recorded
//    `PARTNER` row (unmarried/unknown union), the child is grouped under a
//    synthetic per-parent-pair bucket (keyed by the sorted pair of parent
//    ids) so children are still correctly separated per REQ-TREE-003's
//    acceptance criterion even without a formal partnership record."
//
// This file is DB-free by design, mirroring kinship.ts's "Isolation /
// testability note" precedent (tier-a-contract.md): it operates purely on
// an in-memory array of Relationship-like edges plus a PersonSummary
// lookup. The DB-touching wrapper (loads a Trah's relationships/persons,
// checks the viewer's read permission, then delegates here) lives in
// getTree.ts.
//
// --- Judgment calls (flagged for reviewer) --------------------------------
//
// 1. Tree shape: tier-a/tier-b don't pin an exact TreeGraph shape, only
//    "ancestors/descendants/partners... out to depth generations" plus the
//    REQ-TREE-003 grouping requirement. This implementation returns a
//    root-centered structure: `ancestors` (root's own parents, each
//    recursively holding ITS parents up to `depth` generations) and
//    `descendants` (root's own PartnerBranch[] — buckets of {partner,
//    children}), recursing into each child's own descendant branches up to
//    `depth` generations. This is the natural generalization of tier-b's
//    "parentsOf/childrenOf BFS both directions" description.
//
// 2. Grouping key when a child has more than one recorded co-parent for P
//    (e.g. both a BIOLOGICAL and a STEP parent besides P; an unusual but
//    not-schema-forbidden case): not addressed by tier-b's literal text
//    (which only describes the two-parents-per-child case). Resolved by
//    picking the lexicographically smallest other-parent id, deterministic
//    but not specified — flagged as an extrapolation.
//
// 3. A child with only ONE recorded parent (P) and no co-parent on record
//    at all: grouped under a `partnerId: null` bucket (distinct from any
//    real partner bucket) — tier-b's synthetic-bucket rule is stated for
//    "two parents... no recorded PARTNER row," not for a single-parent
//    case, but the same rationale (don't silently merge distinct
//    situations into one bucket) applies.
//
// 4. depth <= 0: returns a TreeGraph with an empty `ancestors` array and
//    `descendants` array (no generations traversed) — not specified by
//    tier-b, treated as a defensive no-op rather than an error.
__turbopack_context__.s([
    "computeTree",
    ()=>computeTree
]);
function buildParentsOf(edges) {
    const map = new Map();
    for (const edge of edges){
        if (edge.type === "PARTNER" || edge.type === "SIBLING") continue;
        // Directionality (tier-b): personAId = parent, personBId = child.
        const list = map.get(edge.personBId) ?? [];
        list.push({
            parentId: edge.personAId,
            subtype: edge.type
        });
        map.set(edge.personBId, list);
    }
    return map;
}
function buildChildrenOf(edges) {
    const map = new Map();
    for (const edge of edges){
        if (edge.type === "PARTNER" || edge.type === "SIBLING") continue;
        const list = map.get(edge.personAId) ?? [];
        list.push({
            childId: edge.personBId,
            subtype: edge.type
        });
        map.set(edge.personAId, list);
    }
    return map;
}
function buildPartnersOf(edges) {
    const map = new Map();
    const add = (from, to, relationshipId, status)=>{
        const list = map.get(from) ?? [];
        list.push({
            partnerId: to,
            relationshipId,
            status
        });
        map.set(from, list);
    };
    for (const edge of edges){
        if (edge.type !== "PARTNER") continue;
        add(edge.personAId, edge.personBId, edge.relationshipId, edge.partnerStatus ?? null);
        add(edge.personBId, edge.personAId, edge.relationshipId, edge.partnerStatus ?? null);
    }
    return map;
}
function toPersonSummary(personId, persons) {
    return persons.get(personId) ?? {
        id: personId,
        displayName: personId
    };
}
function buildAncestors(personId, generation, depth, parentsOf, persons) {
    if (generation > depth) return [];
    const parents = parentsOf.get(personId) ?? [];
    return parents.map(({ parentId, subtype })=>({
            person: toPersonSummary(parentId, persons),
            generation,
            subtype,
            parents: buildAncestors(parentId, generation + 1, depth, parentsOf, persons)
        }));
}
// REQ-TREE-003: group personId's children into PartnerBranch buckets keyed
// by the OTHER recorded parent (co-parent) of each child, reusing a real
// PARTNER relationship id when one connects personId and that co-parent,
// or a synthetic (partnerId-only) bucket when it doesn't.
function buildDescendantBranches(personId, generation, depth, parentsOf, childrenOf, partnersOf, persons) {
    if (generation > depth) return [];
    const branches = new Map();
    const key = (partnerId)=>partnerId ?? "__NONE__";
    // Seed branches from personId's own recorded partners, even if a given
    // partner has no children on record yet (judgment call #1).
    for (const link of partnersOf.get(personId) ?? []){
        branches.set(key(link.partnerId), {
            partnerId: link.partnerId,
            partner: toPersonSummary(link.partnerId, persons),
            relationshipId: link.relationshipId,
            partnerStatus: link.status,
            children: []
        });
    }
    const children = childrenOf.get(personId) ?? [];
    for (const { childId, subtype } of children){
        const otherParents = (parentsOf.get(childId) ?? []).map((p)=>p.parentId).filter((id)=>id !== personId);
        const uniqueOtherParents = [
            ...new Set(otherParents)
        ].sort();
        const coParentId = uniqueOtherParents.length > 0 ? uniqueOtherParents[0] : null;
        const bucketKey = key(coParentId);
        let branch = branches.get(bucketKey);
        if (!branch) {
            const partnerLink = coParentId ? (partnersOf.get(personId) ?? []).find((l)=>l.partnerId === coParentId) : undefined;
            branch = {
                partnerId: coParentId,
                partner: coParentId ? toPersonSummary(coParentId, persons) : null,
                relationshipId: partnerLink?.relationshipId ?? null,
                partnerStatus: partnerLink?.status ?? null,
                children: []
            };
            branches.set(bucketKey, branch);
        }
        branch.children.push({
            person: toPersonSummary(childId, persons),
            generation,
            subtype,
            partnerBranches: buildDescendantBranches(childId, generation + 1, depth, parentsOf, childrenOf, partnersOf, persons)
        });
    }
    return [
        ...branches.values()
    ];
}
function computeTree(edges, personsInput, rootPersonId, depth) {
    const persons = personsInput instanceof Map ? personsInput : new Map(personsInput.map((p)=>[
            p.id,
            p
        ]));
    const parentsOf = buildParentsOf(edges);
    const childrenOf = buildChildrenOf(edges);
    const partnersOf = buildPartnersOf(edges);
    const root = toPersonSummary(rootPersonId, persons);
    if (depth <= 0) {
        return {
            root,
            ancestors: [],
            descendants: []
        };
    }
    return {
        root,
        ancestors: buildAncestors(rootPersonId, 1, depth, parentsOf, persons),
        descendants: buildDescendantBranches(rootPersonId, 1, depth, parentsOf, childrenOf, partnersOf, persons)
    };
}
}),
"[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/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
    };
}
}),
];

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