{"version":3,"sources":["../../src/jsonld/term-mappings.json","../../src/jsonld/terms.ts","../../src/format/location-utils.ts","../../src/logic/primary-position.ts","../../src/profile/section-model.ts","../../src/jsonld/url.ts","../../src/jsonld/profile.ts","../../src/format/doi.ts","../../src/format/talk-slug.ts","../../src/jsonld/works.ts","../../src/jsonld/works-graph.ts"],"names":["identity","visible"],"mappings":"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","file":"index.cjs","sourcesContent":["{\n  \"$schema\": \"https://sifa.id/schemas/term-mappings/v1.json\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Reconciliation between id.sifa.* lexicon terms and existing RDF vocabularies. RDF is used here as vocabulary only: Sifa records are Lexicon JSON on the AT Protocol, and nothing here changes how they are stored or transmitted. Match strengths use SKOS mapping relations.\",\n  \"vocabularies\": {\n    \"schema\": \"https://schema.org/\",\n    \"bibo\": \"http://purl.org/ontology/bibo/\",\n    \"dcterms\": \"http://purl.org/dc/terms/\",\n    \"foaf\": \"http://xmlns.com/foaf/0.1/\",\n    \"org\": \"http://www.w3.org/ns/org#\",\n    \"prism\": \"http://prismstandard.org/namespaces/basic/2.1/\",\n    \"event\": \"http://purl.org/NET/c4dm/event.owl#\",\n    \"skos\": \"http://www.w3.org/2004/02/skos/core#\"\n  },\n  \"mappings\": [\n    {\n      \"lexicon\": \"id.sifa.org.profile\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:Organization\", \"org:FormalOrganization\"],\n      \"note\": \"ROR is the value anchor.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.certification\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:EducationalOccupationalCredential\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.certification\",\n      \"field\": \"credentialUrl\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:url\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.certification\",\n      \"field\": \"expiresAt\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:validUntil\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.course\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:Course\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.course\",\n      \"field\": \"number\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:courseCode\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.education\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:EducationalOccupationalCredential\"],\n      \"note\": \"One record maps to two schema.org assertions: alumniOf for the institution and hasCredential for the degree.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.education\",\n      \"field\": \"degree\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:hasCredential\", \"bibo:degree\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.education\",\n      \"field\": \"fieldOfStudy\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:educationalCredentialAwarded\"],\n      \"note\": \"ISCED-F is the value anchor.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.education\",\n      \"field\": \"institution\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:alumniOf\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.externalAccount\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:sameAs\", \"foaf:account\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.honor\",\n      \"match\": \"broadMatch\",\n      \"terms\": [\"schema:award\"],\n      \"note\": \"schema:award is a bare string, so issuer and date are lost. No better term exists in BIBO either.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.involvement\",\n      \"match\": \"broadMatch\",\n      \"terms\": [\"org:Membership\"],\n      \"note\": \"The kind known values have no external equivalent.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.language\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:knowsLanguage\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"org:Membership\", \"schema:OrganizationRole\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"company\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"org:organization\", \"schema:worksFor\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"description\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"dcterms:description\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"employmentType\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:employmentType\"],\n      \"note\": \"schema:employmentType is free text. ESCO is the better value anchor.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"endedAt\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:endDate\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"entityRef\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:sameAs\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"location\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:jobLocation\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"startedAt\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:startDate\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"title\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"org:role\", \"schema:roleName\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"workplaceType\",\n      \"match\": \"narrowMatch\",\n      \"terms\": [\"schema:jobLocationType\"],\n      \"note\": \"schema.org models only a remote flag; Sifa distinguishes onSite, remote, and hybrid.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentation\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"bibo:Slideshow\", \"schema:PresentationDigitalDocument\"],\n      \"note\": \"Neither term carries the \\\"reusable, deliverable more than once\\\" semantics of the Sifa record.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentation\",\n      \"field\": \"coverImage\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:image\", \"foaf:depiction\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentation\",\n      \"field\": \"description\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"bibo:abstract\", \"schema:abstract\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentation\",\n      \"field\": \"duration\",\n      \"match\": \"narrowMatch\",\n      \"terms\": [\"schema:timeRequired\"],\n      \"note\": \"The lexicon models a range; schema:timeRequired is a single ISO 8601 duration.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentation\",\n      \"field\": \"intendedAudiences\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:audience\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentation\",\n      \"field\": \"title\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"dcterms:title\", \"schema:name\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentation\",\n      \"field\": \"writeupRef\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"dcterms:isReferencedBy\", \"schema:subjectOf\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:Event\", \"event:Event\"],\n      \"note\": \"BIBO models this relation as bibo:Slideshow bibo:presentedAt event:Event.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"address\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:location\", \"event:place\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"coSpeakers\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:performer\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"date\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:startDate\", \"event:time\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"eventName\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:superEvent\", \"bibo:Conference\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"mode\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:eventAttendanceMode\"],\n      \"note\": \"The community.lexicon.calendar.event known values are already one-to-one with the schema.org enumeration.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"presentationRef\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"bibo:presentedAt\", \"schema:workPerformed\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"role\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"bibo:performer\", \"schema:performer\"],\n      \"note\": \"No external vocabulary distinguishes presenter, panelist, keynote, workshop and host at this granularity.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"status\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:eventStatus\"],\n      \"note\": \"As with mode, already one-to-one with the schema.org enumeration.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.presentationDelivery\",\n      \"field\": \"title\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"dcterms:title\", \"schema:name\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.project\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:Project\", \"foaf:Project\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"match\": \"broadMatch\",\n      \"terms\": [\"bibo:Document\", \"schema:CreativeWork\"],\n      \"note\": \"Refine to bibo:AcademicArticle, bibo:Book, bibo:Report or bibo:Thesis when a resource type is known. COAR is the value anchor.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"authors\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"bibo:authorList\", \"schema:author\"],\n      \"note\": \"bibo:authorList is an ordered rdf:List and preserves author order, which schema:author does not guarantee.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"description\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"bibo:abstract\", \"schema:abstract\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"publishedAt\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"dcterms:issued\", \"schema:datePublished\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"publisher\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"dcterms:publisher\", \"schema:publisher\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"subtitle\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:alternativeHeadline\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"title\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"dcterms:title\", \"schema:name\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"url\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"bibo:uri\", \"schema:url\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:Person\", \"foaf:Person\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"about\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:description\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"avatar\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:image\", \"foaf:depiction\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"displayName\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:name\", \"foaf:name\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"familyName\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:familyName\", \"foaf:family_name\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"givenName\",\n      \"match\": \"exactMatch\",\n      \"terms\": [\"schema:givenName\", \"foaf:givenname\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"headline\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:jobTitle\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"location\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:homeLocation\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.skill\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"schema:knowsAbout\", \"schema:DefinedTerm\"],\n      \"note\": \"ESCO is the value anchor.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.volunteering\",\n      \"match\": \"closeMatch\",\n      \"terms\": [\"org:Membership\", \"schema:OrganizationRole\"]\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.publication\",\n      \"field\": \"doi\",\n      \"terms\": [\"bibo:doi\", \"prism:doi\"],\n      \"match\": \"exactMatch\",\n      \"note\": \"Present on the AppView view type (ORCID-sourced), not yet on the id.sifa.profile.publication lexicon, so user-authored publications cannot carry one.\"\n    }\n  ],\n  \"unmapped\": [\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"pronouns\",\n      \"reason\": \"No stable external term. schema.org has no pronouns property.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.self\",\n      \"field\": \"discoverable\",\n      \"reason\": \"Sifa indexing control, not a fact about the person.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.position\",\n      \"field\": \"isPrimary\",\n      \"reason\": \"Sifa display ordering concern.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.education\",\n      \"field\": \"grade\",\n      \"reason\": \"No comparable external term; grading scales are not portable.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.profile.language\",\n      \"field\": \"proficiency\",\n      \"reason\": \"The known values are CEFR-shaped but not CEFR-named. Map only; renaming a published lexicon for a cosmetic gain is not worth the break.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.confirmation\",\n      \"reason\": \"A record affirming another record is reification. schema:Review and schema:ClaimReview both imply an evaluation that a confirmation does not make.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.endorsement\",\n      \"reason\": \"Same reification problem as confirmation. Any mapping that lets a consumer aggregate endorsements into a score works against the descriptive-only trust model.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.graph.connection\",\n      \"reason\": \"foaf:knows carries no consent semantics. A Sifa connection is bilateral and confirmed; flattening it to foaf:knows would misrepresent an unconfirmed acquaintance claim as mutual.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.graph.follow\",\n      \"reason\": \"See id.sifa.graph.connection.\"\n    },\n    {\n      \"lexicon\": \"id.sifa.meeting\",\n      \"reason\": \"Attestation semantics; same reification problem as confirmation.\"\n    }\n  ]\n}\n","/**\n * Reconciliation between `id.sifa.*` lexicon terms and existing RDF\n * vocabularies.\n *\n * The facts live in sifa-lexicons, as `x-skos:*` annotations on the lexicon\n * defs and properties. Those annotations are published to the authority PDS,\n * so a third party resolving `id.sifa.*` already reads them; that makes the\n * lexicons the source of truth and `./term-mappings.json` a derived copy,\n * refreshed by `scripts/sync-term-mappings.mjs` and drift-checked in CI.\n *\n * To change a mapping, change the lexicon, not this file.\n *\n * Scope note: RDF is adopted here as *vocabulary only*. Sifa records are\n * Lexicon JSON on the AT Protocol; nothing in this module changes how records\n * are stored or transmitted. A mapping is a one-directional annotation over a\n * lexicon designed on its own merits, never a constraint on lexicon design.\n * When a term does not fit, the correct answer is `noMatch`, not a different\n * lexicon.\n */\n\nimport document from './term-mappings.json';\n\n/** Vocabulary prefix -> namespace IRI. */\nexport const VOCABULARIES: Readonly<Record<string, string>> = document.vocabularies;\n\nexport type VocabularyPrefix = keyof typeof document.vocabularies;\n\n/**\n * Strength of a mapping, using SKOS mapping relations so the table is itself\n * expressible as RDF.\n *\n * `noMatch` is not the absence of an entry. It is a deliberate statement that\n * no external term should be used for this concept, and it carries a reason.\n */\nexport type MatchStrength =\n  'exactMatch' | 'closeMatch' | 'broadMatch' | 'narrowMatch' | 'relatedMatch' | 'noMatch';\n\nexport interface TermMapping {\n  /** Lexicon NSID, e.g. `id.sifa.profile.presentation`. */\n  readonly lexicon: string;\n  /**\n   * Field name within the record. Omitted for a record-level class mapping\n   * (what the record *is*, rather than what one of its fields means).\n   */\n  readonly field?: string;\n  /** CURIEs, e.g. `dcterms:title`. Empty when `match` is `noMatch`. */\n  readonly terms: readonly string[];\n  readonly match: MatchStrength;\n  /** Rationale. Always present when `match` is `noMatch`. */\n  readonly note?: string;\n}\n\ninterface RawMapping {\n  lexicon: string;\n  field?: string;\n  terms: string[];\n  match: string;\n  note?: string;\n}\n\ninterface RawUnmapped {\n  lexicon: string;\n  field?: string;\n  reason: string;\n}\n\n/**\n * Every reconciliation Sifa asserts, including the deliberate non-mappings.\n *\n * The published document splits these into `mappings` and `unmapped`, which\n * reads better over the wire. Callers here want one list, so they are\n * flattened back together.\n */\nexport const TERM_MAPPINGS: readonly TermMapping[] = [\n  ...(document.mappings as RawMapping[]).map((m): TermMapping => ({\n    lexicon: m.lexicon,\n    ...(m.field ? { field: m.field } : {}),\n    terms: m.terms,\n    match: m.match as MatchStrength,\n    ...(m.note ? { note: m.note } : {}),\n  })),\n  ...(document.unmapped as RawUnmapped[]).map((u): TermMapping => ({\n    lexicon: u.lexicon,\n    ...(u.field ? { field: u.field } : {}),\n    terms: [],\n    match: 'noMatch',\n    note: u.reason,\n  })),\n];\n\n/**\n * Expand a CURIE (`dcterms:title`) to a full IRI. Returns null for an unknown\n * prefix rather than guessing a namespace.\n */\nexport function expandCurie(curie: string): string | null {\n  const separator = curie.indexOf(':');\n  if (separator <= 0) return null;\n  const prefix = curie.slice(0, separator);\n  const local = curie.slice(separator + 1);\n  if (!local) return null;\n  if (!Object.prototype.hasOwnProperty.call(VOCABULARIES, prefix)) return null;\n  return `${VOCABULARIES[prefix]}${local}`;\n}\n\n/** All mappings declared for one lexicon NSID, record level and field level. */\nexport function mappingsForLexicon(nsid: string): readonly TermMapping[] {\n  return TERM_MAPPINGS.filter((m) => m.lexicon === nsid);\n}\n\n/** True when Sifa has deliberately declined to map this lexicon or field. */\nexport function isDeliberatelyUnmapped(nsid: string, field?: string): boolean {\n  return TERM_MAPPINGS.some(\n    (m) => m.lexicon === nsid && m.field === field && m.match === 'noMatch',\n  );\n}\n","import type { LocationValue } from '../types/index.js';\n\n/**\n * Format a LocationValue for display.\n *\n * Prefers `locality` (the community.lexicon.location.address field) and\n * falls back to the legacy `city` slot so values produced before the\n * sifa-api alias migration still render correctly during the additive\n * transition window.\n */\nexport function formatLocation(loc: LocationValue | null | undefined): string {\n  if (!loc) return '';\n  const locality = loc.locality ?? loc.city;\n  const parts = [locality, loc.region, loc.country].filter(Boolean);\n  if (loc.postalCode && !locality) {\n    return `${loc.postalCode}, ${loc.country}`;\n  }\n  return parts.join(', ');\n}\n\n/** Parse a display string back into a LocationValue (best-effort for legacy data) */\nexport function parseLocationString(str: string): LocationValue | null {\n  if (!str.trim()) return null;\n  const parts = str\n    .split(',')\n    .map((p) => p.trim())\n    .filter(Boolean);\n  if (parts.length >= 3) {\n    return {\n      city: parts[0],\n      region: parts[1],\n      country: parts[parts.length - 1]!,\n    };\n  }\n  if (parts.length === 2) {\n    return {\n      city: parts[0],\n      country: parts[1]!,\n    };\n  }\n  return { country: parts[0]! };\n}\n\n/** Convert ISO 3166-1 alpha-2 country code to flag emoji */\nexport function countryCodeToFlag(code: string | undefined): string {\n  if (!code || code.length !== 2) return '';\n  const upper = code.toUpperCase();\n  const a = upper.codePointAt(0);\n  const b = upper.codePointAt(1);\n  if (a === undefined || b === undefined) return '';\n  return String.fromCodePoint(a - 0x41 + 0x1f1e6, b - 0x41 + 0x1f1e6);\n}\n","/**\n * Canonical rule for picking the \"primary\" position to surface on profile cards,\n * social previews, and structured-data outputs.\n *\n * Without this shared helper, different surfaces (visible hero, OG image,\n * <meta description>, JSON-LD) re-derived \"primary\" inconsistently and diverged\n * for users with multiple concurrent roles.\n *\n * A `hidden` position is one the user chose not to show on their public profile.\n * It is never surfaced as the featured role — hidden wins over `primary`, so a\n * role flagged both hidden and primary is excluded rather than featured.\n *\n * Rules (in order):\n * 1. A position the user explicitly flagged `primary` AND that is still active AND not hidden.\n * 2. Otherwise, the active, non-hidden position with the most recent `startedAt`.\n * 3. Otherwise, undefined (no eligible position).\n */\n\nexport interface PrimaryPositionCandidate {\n  startedAt?: string;\n  endedAt?: string;\n  primary?: boolean;\n  hidden?: boolean;\n}\n\nexport function pickPrimaryPosition<T extends PrimaryPositionCandidate>(\n  positions: readonly T[] | undefined,\n): T | undefined {\n  if (!positions || positions.length === 0) return undefined;\n\n  const active = positions.filter((p) => !p.endedAt && !p.hidden);\n  if (active.length === 0) return undefined;\n\n  const flagged = active.find((p) => p.primary === true);\n  if (flagged) return flagged;\n\n  return [...active].sort((a, b) => (b.startedAt ?? '').localeCompare(a.startedAt ?? ''))[0];\n}\n","/**\n * Shared, single-source-of-truth model for which profile sections render, in\n * what order, their nav grouping, and which items a given viewer may see.\n *\n * Every Sifa profile surface builds on this: the HTML profile page, the\n * Markdown / DOCX / print exports, and the standalone personal-site renderer.\n * Adding a section to {@link ALL_SECTIONS} makes it appear everywhere (the\n * exports drive presence + order from here, and {@link SECTION_LABELS} is an\n * exhaustive `Record<SectionId, string>`, so a new id is a compile error until\n * it has a label).\n *\n * The per-section sorts live in `./section-sorts.js`, built on the same SDK\n * date extractors the HTML section components use, so the surfaces cannot\n * diverge on ordering.\n */\n\nimport type { Profile } from '../types/index.js';\n\n/**\n * Side-nav groups, in display order. Each labels a contiguous run of sections\n * in {@link ALL_SECTIONS}. `labelKey` resolves against the consumer's `sections`\n * i18n namespace.\n */\nexport const SECTION_GROUPS = [\n  { id: 'overview', labelKey: 'groupOverview' },\n  { id: 'experience', labelKey: 'groupExperience' },\n  { id: 'qualifications', labelKey: 'groupQualifications' },\n  { id: 'more', labelKey: 'groupMore' },\n] as const;\n\nexport type SectionGroupId = (typeof SECTION_GROUPS)[number]['id'];\n\n/**\n * Profile body sections in render + nav order (evidence-first): identity and\n * activity lead, then living work (career, skills, projects, talks,\n * publications), then the formal record (credentials, education, courses), then\n * the rest. `ns` selects the consumer's i18n namespace for `labelKey`; `group`\n * ties the section to a {@link SECTION_GROUPS} header.\n */\nexport const ALL_SECTIONS = [\n  { id: 'about', labelKey: 'about', ns: 'profile' as const, group: 'overview' as const },\n  { id: 'career', labelKey: 'career', ns: 'sections' as const, group: 'experience' as const },\n  { id: 'skills', labelKey: 'skills', ns: 'sections' as const, group: 'experience' as const },\n  { id: 'projects', labelKey: 'projects', ns: 'sections' as const, group: 'experience' as const },\n  {\n    id: 'presentations',\n    labelKey: 'talksAndSessions',\n    ns: 'sections' as const,\n    group: 'experience' as const,\n  },\n  {\n    id: 'publications',\n    labelKey: 'publications',\n    ns: 'sections' as const,\n    group: 'experience' as const,\n  },\n  {\n    id: 'credentials',\n    labelKey: 'credentials',\n    ns: 'sections' as const,\n    group: 'qualifications' as const,\n  },\n  {\n    id: 'education',\n    labelKey: 'education',\n    ns: 'sections' as const,\n    group: 'qualifications' as const,\n  },\n  { id: 'courses', labelKey: 'courses', ns: 'sections' as const, group: 'qualifications' as const },\n  { id: 'awards', labelKey: 'awards', ns: 'sections' as const, group: 'more' as const },\n  { id: 'involvement', labelKey: 'involvement', ns: 'sections' as const, group: 'more' as const },\n  // Its own section rather than a group under involvement: that record is about\n  // work contributed, this one about capital deployed.\n  { id: 'investments', labelKey: 'investments', ns: 'sections' as const, group: 'more' as const },\n  { id: 'languages', labelKey: 'languages', ns: 'sections' as const, group: 'more' as const },\n  {\n    id: 'other-profiles',\n    labelKey: 'otherProfiles',\n    ns: 'sections' as const,\n    group: 'more' as const,\n  },\n] as const;\n\n/** Every profile section id, in canonical render order. */\nexport type SectionId = (typeof ALL_SECTIONS)[number]['id'];\n\n/** Whether a section has content for a given profile (used to hide empty nav entries for visitors). */\nexport function isSectionPopulated(profile: Profile, id: string): boolean {\n  switch (id) {\n    case 'about':\n      return Boolean(profile.about && profile.headline);\n    case 'career':\n      return Boolean(profile.positions?.length);\n    case 'education':\n      return Boolean(profile.education?.length);\n    case 'courses':\n      return Boolean(profile.courses?.length);\n    case 'skills':\n      return Boolean(profile.skills?.length);\n    case 'projects':\n      return Boolean(profile.projects?.length);\n    case 'credentials':\n      return Boolean(profile.certifications?.length);\n    case 'publications':\n      return Boolean(profile.publications?.length);\n    case 'presentations':\n      return (\n        Boolean(profile.presentations?.length) || Boolean(profile.presentationDeliveries?.length)\n      );\n    case 'involvement':\n      return Boolean(profile.involvement?.length);\n    case 'investments':\n      return Boolean(profile.investments?.length);\n    case 'awards':\n      return Boolean(profile.honors?.length);\n    case 'languages':\n      return Boolean(profile.languages?.length);\n    case 'other-profiles':\n      return Boolean(profile.externalAccounts?.length);\n    default:\n      return false;\n  }\n}\n\n/**\n * The section ids a given viewer should see, in {@link ALL_SECTIONS} order.\n * Owners see every section; visitors only see populated ones.\n */\nexport function getVisibleSectionIds(profile: Profile, isOwnProfile: boolean): SectionId[] {\n  return ALL_SECTIONS.map((s) => s.id).filter(\n    (id) => isOwnProfile || isSectionPopulated(profile, id),\n  );\n}\n\n/** Drop items the owner has hidden from visitors. */\nexport function filterHidden<T extends { hidden?: boolean }>(items: T[] | undefined): T[] {\n  return (items ?? []).filter((i) => !i.hidden);\n}\n\n/**\n * Items visible to a given viewer: owners see their own hidden items, visitors\n * do not. Shared by every export format (markdown, docx, print) and the public\n * `.md` route so the hidden rule lives in one place.\n */\nexport function visibleItems<T extends { hidden?: boolean }>(\n  items: T[] | undefined,\n  isOwnProfile: boolean,\n): T[] {\n  return isOwnProfile ? (items ?? []) : filterHidden(items);\n}\n\n/**\n * English heading text for each section, keyed by {@link SectionId} (e.g.\n * `other-profiles` renders as \"Links\"). Exhaustive `Record<SectionId, string>`:\n * adding a section to {@link ALL_SECTIONS} without a label here is a compile\n * error, so a section can never silently render without (or with a stale)\n * heading. Consumers with i18n resolve their own localized labels via\n * `labelKey`; this is the canonical English fallback used by the exports.\n */\nexport const SECTION_LABELS: Record<SectionId, string> = {\n  about: 'About',\n  career: 'Career',\n  skills: 'Skills',\n  projects: 'Projects',\n  presentations: 'Talks & sessions',\n  publications: 'Publications',\n  credentials: 'Credentials',\n  education: 'Education',\n  courses: 'Courses',\n  awards: 'Awards',\n  involvement: 'Involvement',\n  investments: 'Investments',\n  languages: 'Languages',\n  'other-profiles': 'Links',\n};\n","/** Shared URL helpers for the JSON-LD emitters. */\n\nexport const DEFAULT_BASE_URL = 'https://sifa.id';\n\n/**\n * Drop trailing slashes from a caller-supplied base URL.\n *\n * Written as a scan rather than `replace(/\\/+$/, '')` on purpose: the regex\n * form is a polynomial-backtracking hazard on input the library does not\n * control (CodeQL js/polynomial-redos). This runs in linear time.\n */\nexport function normaliseBaseUrl(baseUrl: string | undefined): string {\n  const value = baseUrl ?? DEFAULT_BASE_URL;\n  let end = value.length;\n  while (end > 0 && value.charCodeAt(end - 1) === 0x2f) end -= 1;\n  return value.slice(0, end);\n}\n\nexport function profileUrl(baseUrl: string, handle: string): string {\n  return `${baseUrl}/p/${handle}`;\n}\n","/**\n * Schema.org JSON-LD for a Sifa profile.\n *\n * Ported from sifa-web's `src/lib/jsonld.ts` so that sifa.id, page.sifa.id and\n * any future consumer emit the same graph from one implementation. Term choices\n * are recorded in `./terms.js`.\n *\n * These are pure functions: no fetching, no DOM, no framework.\n */\n\nimport { formatLocation } from '../format/location-utils.js';\nimport { pickPrimaryPosition } from '../logic/primary-position.js';\nimport { filterHidden } from '../profile/section-model.js';\nimport type { LocationValue } from '../types/index.js';\nimport { normaliseBaseUrl } from './url.js';\n\n/**\n * Maximum number of skills emitted into `knowsAbout`. The rendered profile\n * still shows every skill; only this structured-data slot is capped so a\n * profile with many skills does not read as keyword stuffing.\n */\nconst MAX_KNOWS_ABOUT = 20;\n\n/**\n * Treat headlines and about text as meaningful only when they contain at least\n * one letter or digit. Profiles carry headlines that are a single emoji and\n * about fields that are a zero-width space; feeding those to `jobTitle` or\n * `description` produces garbage for crawlers.\n */\nconst MEANINGFUL_TEXT_RE = /[\\p{L}\\p{N}]/u;\n\nexport type Sanitizer = (input: string) => string;\n\nexport interface JsonLdOptions {\n  /** Canonical origin for profile URLs. Defaults to `https://sifa.id`. */\n  readonly baseUrl?: string;\n  /** Applied to every user-authored string. Defaults to identity. */\n  readonly sanitize?: Sanitizer;\n  /**\n   * Absolute URL of the page this graph describes, used for `url` and `@id`.\n   * Defaults to `${baseUrl}/p/${handle}`. Personal sites can be served from an\n   * arbitrary host, including a self-hosted custom domain, where that default\n   * path is not where the page lives.\n   */\n  readonly canonicalUrl?: string;\n}\n\n/**\n * Structural input for the emitters.\n *\n * Deliberately looser than `Profile`: it accepts a `Profile` unchanged, but\n * also the partial shapes held by consumers that render a subset (page.sifa.id)\n * without forcing them to fabricate required fields.\n */\nexport interface JsonLdProfileInput {\n  readonly handle: string;\n  readonly displayName?: string;\n  readonly givenName?: string;\n  readonly familyName?: string;\n  readonly headline?: string;\n  readonly about?: string;\n  readonly avatar?: string;\n  readonly website?: string;\n  readonly location?: LocationValue | null;\n  readonly updatedAt?: string;\n  readonly positions?: readonly JsonLdPosition[];\n  readonly education?: readonly JsonLdEducation[];\n  readonly skills?: readonly JsonLdSkill[];\n  readonly certifications?: readonly JsonLdCertification[];\n  readonly volunteering?: readonly JsonLdVolunteering[];\n  readonly honors?: readonly JsonLdHonor[];\n  readonly languages?: readonly JsonLdLanguage[];\n  readonly verifiedAccounts?: readonly { platform: string; identifier: string; url?: string }[];\n  readonly activeApps?: readonly { id: string }[];\n  /** Only the length is read, to decide which section anchors to advertise. */\n  readonly projects?: readonly unknown[];\n  readonly publications?: readonly unknown[];\n  readonly courses?: readonly unknown[];\n  readonly externalAccounts?: readonly unknown[];\n  /**\n   * Dual-facet accounts: one DID presenting as both a person and a company.\n   * Only the opted-in case is emitted, see `buildPersonJsonLd`.\n   */\n  readonly org?: {\n    readonly personalProfileVisible?: boolean;\n    readonly orgProfile?: { readonly name?: string } | null;\n  } | null;\n}\n\ninterface Hideable {\n  readonly hidden?: boolean;\n}\nexport interface JsonLdPosition extends Hideable {\n  readonly company?: string;\n  /**\n   * Current canonical name of the linked company entity, resolved by the\n   * AppView at read time. Preferred over the free-text `company` snapshot for\n   * `worksFor.name` so structured data names the corrected (and decoded) entity.\n   */\n  readonly entityName?: string;\n  readonly title?: string;\n  readonly startedAt?: string;\n  readonly endedAt?: string;\n  readonly description?: string;\n  readonly primary?: boolean;\n}\nexport interface JsonLdEducation extends Hideable {\n  readonly institution?: string;\n  readonly degree?: string;\n  readonly fieldOfStudy?: string;\n}\nexport interface JsonLdSkill extends Hideable {\n  readonly name?: string;\n  readonly endorsementCount?: number;\n}\nexport interface JsonLdCertification extends Hideable {\n  readonly name?: string;\n  readonly authority?: string;\n  readonly issuingOrg?: string;\n  readonly credentialUrl?: string;\n}\nexport interface JsonLdVolunteering extends Hideable {\n  readonly organization?: string;\n  readonly role?: string;\n  readonly startDate?: string;\n  readonly endDate?: string;\n}\nexport interface JsonLdHonor extends Hideable {\n  readonly title?: string;\n}\nexport interface JsonLdLanguage extends Hideable {\n  readonly language?: string;\n}\n\nconst identity: Sanitizer = (input) => input;\n\nfunction hasMeaningfulText(value: string | undefined | null): value is string {\n  return typeof value === 'string' && MEANINGFUL_TEXT_RE.test(value);\n}\n\n/** `filterHidden` takes a mutable array; the input types are readonly. */\nfunction visible<T extends Hideable>(items: readonly T[] | undefined): T[] {\n  return filterHidden(items ? [...items] : undefined);\n}\n\n/**\n * Selects and ranks the skills surfaced in `knowsAbout`. Ordered by endorsement\n * count descending, a missing count counting as zero, ties preserving input\n * order. Returns undefined when no named skill exists so the property is\n * omitted entirely rather than emitted empty.\n */\nfunction rankKnowsAbout(\n  skills: readonly JsonLdSkill[] | undefined,\n  s: Sanitizer,\n): string[] | undefined {\n  const ranked = visible(skills)\n    .filter((sk): sk is JsonLdSkill & { name: string } => Boolean(sk.name))\n    .sort((a, b) => (b.endorsementCount ?? 0) - (a.endorsementCount ?? 0))\n    .slice(0, MAX_KNOWS_ABOUT)\n    .map((sk) => s(sk.name));\n\n  return ranked.length > 0 ? ranked : undefined;\n}\n\nfunction buildSameAs(profile: JsonLdProfileInput): string[] {\n  const sameAs: string[] = [];\n\n  // ATproto is multi-app: a Sifa identity may hold no Bluesky records at all.\n  // Only link bsky.app when activeApps confirms Bluesky presence, otherwise the\n  // link points at an empty profile and weakens entity resolution rather than\n  // strengthening it.\n  const hasBluesky = profile.activeApps?.some((a) => a.id === 'bluesky') ?? false;\n  if (hasBluesky) sameAs.push(`https://bsky.app/profile/${profile.handle}`);\n\n  if (profile.website) {\n    const url = profile.website.startsWith('http') ? profile.website : `https://${profile.website}`;\n    if (!sameAs.includes(url)) sameAs.push(url);\n  }\n\n  for (const account of profile.verifiedAccounts ?? []) {\n    if (account.url && !sameAs.includes(account.url)) sameAs.push(account.url);\n  }\n\n  return sameAs;\n}\n\nfunction buildHomeLocation(location: LocationValue, s: Sanitizer) {\n  // Emit the address sub-object when either a country code or a locality is\n  // present. Locality prefers the community-shape `locality` with a fallback to\n  // the legacy `city` so output stays correct whichever shape the AppView emits.\n  const addressLocality = location.locality ?? location.city;\n  const addressCountry = location.countryCode;\n  const hasAddress = Boolean(addressLocality) || Boolean(addressCountry);\n\n  return {\n    '@type': 'Place' as const,\n    name: s(formatLocation(location)),\n    ...(hasAddress && {\n      address: {\n        '@type': 'PostalAddress' as const,\n        ...(addressLocality && { addressLocality: s(addressLocality) }),\n        ...(addressCountry && { addressCountry }),\n      },\n    }),\n  };\n}\n\nexport function buildPersonJsonLd(profile: JsonLdProfileInput, options: JsonLdOptions = {}) {\n  const s = options.sanitize ?? identity;\n  const baseUrl = normaliseBaseUrl(options.baseUrl);\n  // The own-company link below deliberately keeps the baseUrl origin: a /c/\n  // page lives on Sifa even when the personal site does not.\n  const canonical = options.canonicalUrl ?? `${baseUrl}/p/${profile.handle}`;\n\n  const positions = visible(profile.positions);\n  const currentPosition = pickPrimaryPosition(positions);\n  const knowsAbout = rankKnowsAbout(profile.skills, s);\n  const sameAs = buildSameAs(profile);\n\n  const hasCredential = [\n    ...visible(profile.education)\n      .filter((e) => e.degree)\n      .map((e) => ({\n        '@type': 'EducationalOccupationalCredential' as const,\n        credentialCategory: 'degree' as const,\n        name: [e.degree, e.fieldOfStudy].filter(Boolean).join(' '),\n        ...(e.institution && {\n          recognizedBy: { '@type': 'EducationalOrganization' as const, name: s(e.institution) },\n        }),\n      })),\n    ...visible(profile.certifications)\n      .filter((c) => c.name)\n      .map((c) => ({\n        '@type': 'EducationalOccupationalCredential' as const,\n        name: s(c.name!),\n        ...((c.authority ?? c.issuingOrg) && {\n          recognizedBy: {\n            '@type': 'Organization' as const,\n            name: s((c.authority ?? c.issuingOrg)!),\n          },\n        }),\n        ...(c.credentialUrl && { url: c.credentialUrl }),\n      })),\n  ];\n\n  // Prefer the structured name when both halves are present so `name` stays\n  // consistent with the explicit givenName/familyName properties.\n  const givenTrimmed = profile.givenName?.trim();\n  const familyTrimmed = profile.familyName?.trim();\n  const structuredName =\n    givenTrimmed && familyTrimmed ? `${givenTrimmed} ${familyTrimmed}` : undefined;\n\n  // A sole trader who kept both faces is one legal person and one business on\n  // a single DID. Without an explicit link a crawler reads the /p/ Person and\n  // the /c/ Organization as two unrelated entities that happen to share a\n  // domain. The company goes first: it is the account's own business, ahead of\n  // any self-reported position elsewhere.\n  const ownCompany =\n    profile.org?.personalProfileVisible && profile.org.orgProfile\n      ? {\n          '@type': 'Organization' as const,\n          '@id': `${baseUrl}/c/${profile.handle}`,\n          name: s(profile.org.orgProfile.name ?? profile.handle),\n        }\n      : null;\n  const worksFor = [\n    ...(ownCompany ? [ownCompany] : []),\n    ...positions\n      .filter((p) => p.entityName ?? p.company)\n      .map((p) => ({\n        '@type': 'Organization' as const,\n        name: s((p.entityName ?? p.company)!),\n        ...(p.title && {\n          member: {\n            '@type': 'OrganizationRole' as const,\n            roleName: s(p.title),\n            ...(p.startedAt && { startDate: p.startedAt }),\n            ...(p.endedAt && { endDate: p.endedAt }),\n          },\n        }),\n      })),\n  ];\n\n  const awards = visible(profile.honors)\n    .filter((h) => h.title)\n    .map((h) => s(h.title!));\n  const languages = visible(profile.languages)\n    .filter((l) => l.language)\n    .map((l) => l.language!);\n\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'Person',\n    // Stable identifier so a /c/ Organization's `founder` can point back here.\n    '@id': canonical,\n    name: s(structuredName ?? profile.displayName ?? profile.handle),\n    ...(givenTrimmed && { givenName: s(givenTrimmed) }),\n    ...(familyTrimmed && { familyName: s(familyTrimmed) }),\n    jobTitle: hasMeaningfulText(profile.headline)\n      ? s(profile.headline)\n      : currentPosition?.title\n        ? s(currentPosition.title)\n        : undefined,\n    description: hasMeaningfulText(profile.about) ? s(profile.about) : undefined,\n    alternateName: `@${profile.handle}`,\n    url: canonical,\n    image: profile.avatar ?? undefined,\n    ...(profile.location && { homeLocation: buildHomeLocation(profile.location, s) }),\n    ...(worksFor.length > 0 && { worksFor }),\n    ...(visible(profile.education).length > 0 && {\n      alumniOf: visible(profile.education)\n        .filter((e) => e.institution)\n        .map((e) => ({ '@type': 'EducationalOrganization' as const, name: s(e.institution!) })),\n    }),\n    ...(hasCredential.length > 0 && { hasCredential }),\n    ...(visible(profile.volunteering).length > 0 && {\n      memberOf: visible(profile.volunteering)\n        .filter((v) => v.organization)\n        .map((v) => ({\n          '@type': 'OrganizationRole' as const,\n          memberOf: { '@type': 'Organization' as const, name: s(v.organization!) },\n          ...(v.role && { roleName: s(v.role) }),\n          ...(v.startDate && { startDate: v.startDate }),\n          ...(v.endDate && { endDate: v.endDate }),\n        })),\n    }),\n    ...(awards.length > 0 && { award: awards }),\n    ...(languages.length > 0 && { knowsLanguage: languages }),\n    ...(knowsAbout && { knowsAbout }),\n    ...(sameAs.length > 0 && { sameAs }),\n  };\n}\n\n/**\n * Section anchors are a soft public API: third-party tools link to `#career`,\n * `#languages` and friends. Renaming one is a breaking change. Each id MUST\n * match the DOM id rendered by the consuming app.\n */\nconst PROFILE_SECTION_HAS_PART: readonly {\n  id: string;\n  label: string;\n  populated: (p: JsonLdProfileInput) => boolean;\n}[] = [\n  { id: 'about', label: 'About', populated: (p) => Boolean(p.about && p.headline) },\n  { id: 'career', label: 'Career', populated: (p) => visible(p.positions).length > 0 },\n  { id: 'education', label: 'Education', populated: (p) => visible(p.education).length > 0 },\n  { id: 'projects', label: 'Projects', populated: (p) => (p.projects?.length ?? 0) > 0 },\n  {\n    id: 'credentials',\n    label: 'Credentials',\n    populated: (p) => visible(p.certifications).length > 0,\n  },\n  {\n    id: 'publications',\n    label: 'Publications',\n    populated: (p) => (p.publications?.length ?? 0) > 0,\n  },\n  {\n    id: 'volunteering',\n    label: 'Volunteering',\n    populated: (p) => visible(p.volunteering).length > 0,\n  },\n  { id: 'awards', label: 'Awards', populated: (p) => visible(p.honors).length > 0 },\n  { id: 'languages', label: 'Languages', populated: (p) => visible(p.languages).length > 0 },\n  { id: 'skills', label: 'Skills', populated: (p) => visible(p.skills).length > 0 },\n  {\n    id: 'other-profiles',\n    label: 'Other profiles',\n    populated: (p) => (p.externalAccounts?.length ?? 0) > 0,\n  },\n];\n\nexport function buildProfilePageJsonLd(profile: JsonLdProfileInput, options: JsonLdOptions = {}) {\n  const person = buildPersonJsonLd(profile, options);\n  const { '@context': _context, ...personWithoutContext } = person;\n\n  const url = options.canonicalUrl ?? `${normaliseBaseUrl(options.baseUrl)}/p/${profile.handle}`;\n  const hasPart = PROFILE_SECTION_HAS_PART.filter((section) => section.populated(profile)).map(\n    (section) => ({\n      '@type': 'WebPageElement' as const,\n      name: section.label,\n      url: `${url}#${section.id}`,\n    }),\n  );\n\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'ProfilePage' as const,\n    url,\n    ...(profile.updatedAt && { dateModified: profile.updatedAt }),\n    mainEntity: personWithoutContext,\n    ...(hasPart.length > 0 && { hasPart }),\n  };\n}\n\nexport function buildBreadcrumbListJsonLd(\n  profile: Pick<JsonLdProfileInput, 'handle' | 'displayName'>,\n  options: JsonLdOptions = {},\n) {\n  const s = options.sanitize ?? identity;\n  const baseUrl = normaliseBaseUrl(options.baseUrl);\n  const name = s(profile.displayName ?? profile.handle);\n\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'BreadcrumbList' as const,\n    itemListElement: [\n      { '@type': 'ListItem' as const, position: 1, name: 'Sifa', item: `${baseUrl}/` },\n      {\n        '@type': 'ListItem' as const,\n        position: 2,\n        name,\n        item: `${baseUrl}/p/${profile.handle}`,\n      },\n    ],\n  };\n}\n","/**\n * Reduce a DOI to its bare form: `10.1234/example`, never\n * `https://doi.org/10.1234/example` and never `doi:10.1234/example`.\n *\n * A DOI inside a URL is a link. Bare, it is an identifier, which is what lets\n * two records describing one publication be matched on it. The lexicon stores\n * the bare form for that reason.\n *\n * People paste the resolver URL, because that is what a publisher page and a\n * citation manager both hand you, and citations carry the `doi:` scheme.\n * Normalizing on the way in is the difference between a field that dedupes and\n * a field holding three spellings of one value.\n *\n * Input that is not a DOI at all is trimmed and returned as-is. This is a\n * normalizer, not a validator: rejecting here would fail a write over a field\n * nothing depends on, and older registrants produce shapes worth not policing.\n */\nexport function normalizeDoi(value: string): string {\n  return value\n    .trim()\n    .replace(/^https?:\\/\\/(dx\\.)?doi\\.org\\//i, '')\n    .replace(/^doi:\\s*/i, '');\n}\n","/**\n * Slug helpers for talk-page URLs. Pure and offline: a talk page lives at a\n * path like `/{slug}-{rkey}`, where the slug is a human-readable, SEO-friendly\n * rendering of the title and the rkey is the record's stable identifier.\n * Because TIDs never contain a `-`, the rkey can always be recovered as the\n * substring after the final `-`.\n */\n\n/** Maximum slug length before the trailing rkey is appended. */\nconst MAX_SLUG_LENGTH = 60;\n\n/** Combining diacritical marks left behind by NFKD decomposition (U+0300–U+036F). */\nconst COMBINING_MARKS = /[̀-ͯ]/g;\n\n/**\n * Render a title as a URL slug: lowercased, diacritics stripped, runs of\n * non-alphanumerics collapsed to a single `-`, trimmed, and capped at 60 chars.\n * Returns `''` for an empty or whitespace-only title.\n */\nexport function slugifyTitle(title: string): string {\n  const slug = title\n    .normalize('NFKD')\n    // Strip combining marks left by NFKD decomposition (é -> e).\n    .replace(COMBINING_MARKS, '')\n    .toLowerCase()\n    // Collapse any run of non-alphanumerics into a single hyphen.\n    .replace(/[^a-z0-9]+/g, '-')\n    // Collapse repeated hyphens.\n    .replace(/-+/g, '-')\n    // Trim leading/trailing hyphens.\n    .replace(/^-+|-+$/g, '');\n  // Cap length, then trim a trailing hyphen the cut may have exposed.\n  return slug.slice(0, MAX_SLUG_LENGTH).replace(/-+$/g, '');\n}\n\n/**\n * Build the talk-page path segment `${slug}-${rkey}`, or just `rkey` when the\n * title produces an empty slug.\n */\nexport function buildTalkSlug(title: string, rkey: string): string {\n  const slug = slugifyTitle(title);\n  return slug ? `${slug}-${rkey}` : rkey;\n}\n\n/**\n * Recover the rkey from a talk-page segment: the substring after the final `-`\n * (TIDs contain no `-`). Returns the whole segment when there is no `-`.\n */\nexport function parseTalkRkey(segment: string): string {\n  const idx = segment.lastIndexOf('-');\n  return idx === -1 ? segment : segment.slice(idx + 1);\n}\n","/**\n * Schema.org JSON-LD for the things a person made: talks, publications,\n * courses and projects.\n *\n * These collections carried no structured data before this module existed;\n * a talk page emitted a four-property `CreativeWork` and publications,\n * courses and projects emitted nothing at all. Term choices are recorded in\n * `./terms.js`.\n */\n\nimport { normalizeDoi } from '../format/doi.js';\nimport { buildTalkSlug } from '../format/talk-slug.js';\nimport { filterHidden } from '../profile/section-model.js';\nimport { normaliseBaseUrl, profileUrl } from './url.js';\n\nconst DOI_RESOLVER = 'https://doi.org/';\nconst ORCID_RESOLVER = 'https://orcid.org/';\n\nexport interface WorksOptions {\n  readonly baseUrl?: string;\n  readonly sanitize?: (input: string) => string;\n}\n\n/** Minimal identity for the profile owner a work is attributed to. */\nexport interface WorkAuthor {\n  readonly handle: string;\n  readonly displayName?: string;\n}\n\n/**\n * A person named on somebody else's record. `confirmed` is load bearing: an\n * unconfirmed claim is a claim, not a fact, and must never be laundered into\n * structured data as a schema.org Person.\n */\ninterface NamedActor {\n  readonly did?: string;\n  readonly handle?: string;\n  readonly displayName?: string;\n  readonly confirmed?: boolean;\n}\n\ninterface PersonNode {\n  readonly '@type': 'Person';\n  readonly name: string;\n  readonly url?: string;\n  readonly sameAs?: string[];\n}\n\nconst identity = (input: string) => input;\n\nfunction authorNode(author: WorkAuthor, baseUrl: string, s: (v: string) => string): PersonNode {\n  return {\n    '@type': 'Person',\n    name: s(author.displayName ?? author.handle),\n    url: profileUrl(baseUrl, author.handle),\n  };\n}\n\n/**\n * Confirmed named actors only, mapped to Person nodes. Anyone unconfirmed is\n * dropped entirely rather than degraded to a bare handle, because even a handle\n * in structured data asserts the association.\n */\nfunction confirmedActorNodes(\n  actors: readonly NamedActor[] | undefined,\n  baseUrl: string,\n  s: (v: string) => string,\n): PersonNode[] {\n  return (actors ?? [])\n    .filter((a) => a.confirmed === true && Boolean(a.handle))\n    .map((a) => ({\n      '@type': 'Person' as const,\n      name: s(a.displayName ?? a.handle!),\n      url: profileUrl(baseUrl, a.handle!),\n    }));\n}\n\n/** `filterHidden` takes a mutable array; inputs here are readonly. */\nfunction visible<T extends { hidden?: boolean }>(items: readonly T[] | undefined): T[] {\n  return filterHidden(items ? [...items] : undefined);\n}\n\n// ---------------------------------------------------------------------------\n// Presentations\n// ---------------------------------------------------------------------------\n\n/**\n * The community calendar known values are already one-to-one with the\n * schema.org enumerations. An unrecognised value is left off rather than\n * guessed: a wrong attendance mode is worse than a missing one.\n */\nconst ATTENDANCE_MODE: Readonly<Record<string, string>> = {\n  'community.lexicon.calendar.event#inperson': 'https://schema.org/OfflineEventAttendanceMode',\n  'community.lexicon.calendar.event#virtual': 'https://schema.org/OnlineEventAttendanceMode',\n  'community.lexicon.calendar.event#hybrid': 'https://schema.org/MixedEventAttendanceMode',\n};\n\n/**\n * `#planned` is intentionally absent: schema.org has no equivalent, and mapping\n * it to EventScheduled would assert a commitment the record does not make.\n */\nconst EVENT_STATUS: Readonly<Record<string, string>> = {\n  'community.lexicon.calendar.event#scheduled': 'https://schema.org/EventScheduled',\n  'community.lexicon.calendar.event#cancelled': 'https://schema.org/EventCancelled',\n  'community.lexicon.calendar.event#postponed': 'https://schema.org/EventPostponed',\n  'community.lexicon.calendar.event#rescheduled': 'https://schema.org/EventRescheduled',\n};\n\nconst LINK_SLIDES = 'id.sifa.defs#linkSlides';\nconst LINK_RECORDING = 'id.sifa.defs#linkRecording';\n\nexport interface PresentationLinkInput {\n  readonly uri: string;\n  readonly label?: string;\n  readonly type?: string;\n}\n\nexport interface PresentationDeliveryInput {\n  readonly rkey: string;\n  readonly title?: string | null;\n  readonly role?: string | null;\n  readonly eventName?: string | null;\n  readonly date?: string | null;\n  readonly location?: string | null;\n  readonly locationLocality?: string | null;\n  readonly locationRegion?: string | null;\n  readonly countryCode?: string | null;\n  readonly mode?: string | null;\n  readonly status?: string | null;\n  readonly links?: readonly PresentationLinkInput[];\n  readonly coSpeakers?: readonly NamedActor[];\n  readonly hidden?: boolean;\n}\n\nexport interface PresentationInput {\n  readonly rkey: string;\n  readonly title: string;\n  readonly description?: string | null;\n  readonly duration?: { minMinutes: number; maxMinutes?: number } | null;\n  readonly coverImageUrl?: string | null;\n  readonly links?: readonly PresentationLinkInput[];\n  readonly deliveries?: readonly PresentationDeliveryInput[];\n  readonly hidden?: boolean;\n}\n\nfunction lookup(table: Readonly<Record<string, string>>, key: string | null | undefined) {\n  if (!key) return undefined;\n  return Object.prototype.hasOwnProperty.call(table, key) ? table[key] : undefined;\n}\n\nfunction deliveryPlace(delivery: PresentationDeliveryInput, s: (v: string) => string) {\n  const addressLocality = delivery.locationLocality ?? undefined;\n  const addressRegion = delivery.locationRegion ?? undefined;\n  const addressCountry = delivery.countryCode ?? undefined;\n\n  if (addressLocality || addressRegion || addressCountry) {\n    return {\n      '@type': 'Place' as const,\n      address: {\n        '@type': 'PostalAddress' as const,\n        ...(addressLocality && { addressLocality: s(addressLocality) }),\n        ...(addressRegion && { addressRegion: s(addressRegion) }),\n        ...(addressCountry && { addressCountry }),\n      },\n    };\n  }\n\n  // Legacy free-text location, kept so deliveries recorded before the\n  // structured address field still say where they happened.\n  if (delivery.location) {\n    return { '@type': 'Place' as const, name: s(delivery.location) };\n  }\n\n  return undefined;\n}\n\nfunction linkOfType(links: readonly PresentationLinkInput[] | undefined, type: string) {\n  return links?.find((l) => l.type === type)?.uri;\n}\n\nexport function buildPresentationJsonLd(\n  presentation: PresentationInput,\n  author: WorkAuthor,\n  options: WorksOptions = {},\n) {\n  const s = options.sanitize ?? identity;\n  const baseUrl = normaliseBaseUrl(options.baseUrl);\n  const speaker = authorNode(author, baseUrl, s);\n\n  const events = visible(presentation.deliveries).map((delivery) => {\n    const place = deliveryPlace(delivery, s);\n    const recording = linkOfType(delivery.links, LINK_RECORDING);\n    const slides =\n      linkOfType(delivery.links, LINK_SLIDES) ?? linkOfType(presentation.links, LINK_SLIDES);\n\n    return {\n      '@type': 'Event' as const,\n      name: s(delivery.eventName ?? delivery.title ?? presentation.title),\n      ...(delivery.date && { startDate: delivery.date }),\n      ...(place && { location: place }),\n      ...(lookup(ATTENDANCE_MODE, delivery.mode) && {\n        eventAttendanceMode: lookup(ATTENDANCE_MODE, delivery.mode),\n      }),\n      ...(lookup(EVENT_STATUS, delivery.status) && {\n        eventStatus: lookup(EVENT_STATUS, delivery.status),\n      }),\n      performer: [speaker, ...confirmedActorNodes(delivery.coSpeakers, baseUrl, s)],\n      ...(recording && { recordedIn: { '@type': 'VideoObject' as const, url: recording } }),\n      ...(slides && {\n        workFeatured: { '@type': 'PresentationDigitalDocument' as const, url: slides },\n      }),\n    };\n  });\n\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'PresentationDigitalDocument' as const,\n    name: s(presentation.title),\n    ...(presentation.description && { abstract: s(presentation.description) }),\n    ...(presentation.duration && { timeRequired: `PT${presentation.duration.minMinutes}M` }),\n    ...(presentation.coverImageUrl && { image: presentation.coverImageUrl }),\n    author: speaker,\n    url: `${baseUrl}/p/${author.handle}/talk/${buildTalkSlug(presentation.title, presentation.rkey)}`,\n    ...(events.length > 0 && { subjectOf: events }),\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Publications\n// ---------------------------------------------------------------------------\n\nexport interface PublicationContributorInput {\n  readonly name: string;\n  readonly orcidId?: string;\n  readonly handle?: string;\n}\n\nexport interface PublicationInput {\n  readonly rkey: string;\n  readonly title: string;\n  readonly subtitle?: string;\n  readonly publisher?: string;\n  readonly date?: string;\n  readonly url?: string;\n  readonly description?: string;\n  readonly doi?: string;\n  readonly contributors?: readonly PublicationContributorInput[];\n  readonly hidden?: boolean;\n}\n\nexport function buildPublicationJsonLd(\n  publication: PublicationInput,\n  author: WorkAuthor,\n  options: WorksOptions = {},\n) {\n  const s = options.sanitize ?? identity;\n  const baseUrl = normaliseBaseUrl(options.baseUrl);\n\n  // Contributor order is meaningful in scholarly work, so it is preserved as\n  // given rather than sorted or deduplicated.\n  const authors: PersonNode[] =\n    publication.contributors && publication.contributors.length > 0\n      ? publication.contributors.map((c) => ({\n          '@type': 'Person' as const,\n          name: s(c.name),\n          ...(c.handle && { url: profileUrl(baseUrl, c.handle) }),\n          ...(c.orcidId && { sameAs: [`${ORCID_RESOLVER}${c.orcidId}`] }),\n        }))\n      : [authorNode(author, baseUrl, s)];\n\n  const doi = publication.doi ? normalizeDoi(publication.doi) : undefined;\n\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'ScholarlyArticle' as const,\n    name: s(publication.title),\n    ...(publication.subtitle && { alternativeHeadline: s(publication.subtitle) }),\n    ...(publication.description && { abstract: s(publication.description) }),\n    ...(publication.publisher && {\n      publisher: { '@type': 'Organization' as const, name: s(publication.publisher) },\n    }),\n    ...(publication.date && { datePublished: publication.date }),\n    ...(publication.url && { url: publication.url }),\n    author: authors,\n    ...(doi && {\n      identifier: { '@type': 'PropertyValue' as const, propertyID: 'DOI', value: doi },\n      sameAs: [`${DOI_RESOLVER}${doi}`],\n    }),\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Courses and projects\n// ---------------------------------------------------------------------------\n\nexport interface CourseInput {\n  readonly rkey: string;\n  readonly name: string;\n  readonly number?: string;\n  readonly institution?: string;\n  readonly hidden?: boolean;\n}\n\nexport function buildCourseJsonLd(course: CourseInput, options: WorksOptions = {}) {\n  const s = options.sanitize ?? identity;\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'Course' as const,\n    name: s(course.name),\n    ...(course.number && { courseCode: s(course.number) }),\n    ...(course.institution && {\n      provider: { '@type': 'EducationalOrganization' as const, name: s(course.institution) },\n    }),\n  };\n}\n\nexport interface ProjectInput {\n  readonly rkey: string;\n  readonly name: string;\n  readonly description?: string;\n  readonly url?: string;\n  readonly startDate?: string;\n  readonly endDate?: string;\n  readonly members?: readonly NamedActor[];\n  readonly hidden?: boolean;\n}\n\nexport function buildProjectJsonLd(\n  project: ProjectInput,\n  author: WorkAuthor,\n  options: WorksOptions = {},\n) {\n  const s = options.sanitize ?? identity;\n  const baseUrl = normaliseBaseUrl(options.baseUrl);\n  const members = confirmedActorNodes(project.members, baseUrl, s);\n\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'Project' as const,\n    name: s(project.name),\n    ...(project.description && { description: s(project.description) }),\n    ...(project.url && { url: project.url }),\n    ...(project.startDate && { startDate: project.startDate }),\n    ...(project.endDate && { endDate: project.endDate }),\n    member: [authorNode(author, baseUrl, s), ...members],\n  };\n}\n","/**\n * The works on a profile as one JSON-LD `@graph`.\n *\n * A profile page already emits a `ProfilePage` whose `mainEntity` is the\n * Person. Publications, talks, courses and projects are separate entities\n * rather than properties of that Person, so they go in their own block and\n * point back at the Person by `@id` instead of repeating the whole node.\n */\n\nimport { filterHidden } from '../profile/section-model.js';\nimport type { JsonLdOptions } from './profile.js';\nimport { normaliseBaseUrl } from './url.js';\nimport {\n  buildCourseJsonLd,\n  buildPresentationJsonLd,\n  buildProjectJsonLd,\n  buildPublicationJsonLd,\n  type CourseInput,\n  type PresentationInput,\n  type ProjectInput,\n  type PublicationInput,\n  type WorkAuthor,\n} from './works.js';\n\nexport interface ProfileWorksInput {\n  readonly handle: string;\n  readonly publications?: readonly PublicationInput[];\n  readonly presentations?: readonly PresentationInput[];\n  readonly courses?: readonly CourseInput[];\n  readonly projects?: readonly ProjectInput[];\n}\n\n/** `filterHidden` takes a mutable array; inputs here are readonly. */\nfunction visible<T extends { hidden?: boolean }>(items: readonly T[] | undefined): T[] {\n  return filterHidden(items ? [...items] : undefined);\n}\n\n/**\n * Returns null when there is nothing to say, so a caller can skip the script\n * block entirely rather than emitting an empty graph.\n */\nexport function buildProfileWorksJsonLd(\n  profile: ProfileWorksInput,\n  author: WorkAuthor,\n  options: JsonLdOptions = {},\n) {\n  const personId =\n    options.canonicalUrl ?? `${normaliseBaseUrl(options.baseUrl)}/p/${profile.handle}`;\n\n  // Each work is built by its own emitter, then its `@context` is dropped: the\n  // graph carries one context for every node in it.\n  const strip = <T extends { '@context': string }>(node: T) => {\n    const { '@context': _context, ...rest } = node;\n    return rest;\n  };\n\n  // The Person is emitted in full by the ProfilePage block. Referencing it by\n  // `@id` keeps one Person in the graph rather than several partial copies for\n  // a consumer to reconcile.\n  const authorRef = [{ '@id': personId }];\n\n  const graph: Record<string, unknown>[] = [\n    ...visible(profile.publications).map((p) => ({\n      ...strip(buildPublicationJsonLd(p, author, options)),\n      author: authorRef,\n    })),\n    ...visible(profile.presentations).map((p) => ({\n      ...strip(buildPresentationJsonLd(p, author, options)),\n      author: authorRef,\n    })),\n    ...visible(profile.courses).map((c) => strip(buildCourseJsonLd(c, options))),\n    ...visible(profile.projects).map((p) => ({\n      ...strip(buildProjectJsonLd(p, author, options)),\n      member: authorRef,\n    })),\n  ];\n\n  if (graph.length === 0) return null;\n\n  return { '@context': 'https://schema.org', '@graph': graph };\n}\n"]}