diff --git a/lexicons/README.md b/lexicons/README.md index 98fcf10b..c6d3bf62 100644 --- a/lexicons/README.md +++ b/lexicons/README.md @@ -22,6 +22,13 @@ The files under `site/standard/` are copies of the the build-time sync writes to. `com/atproto/label/defs.json` is here because both of them reference `#selfLabels`. +The files under `id/sifa/` are copies of the [Sifa](https://sifa.id) schemas from +[singi-labs/sifa-lexicons](https://github.com/singi-labs/sifa-lexicons), published at +`did:plc:2f2ahswozqy4v5lvu676375y`. `shared/sifa.ts` turns +`id.sifa.profile.presentation`, `id.sifa.profile.presentationDelivery` and +`id.sifa.profile.project` into collections, which the build-time sync mirrors +from `dev.roe.talkGroup`, `dev.roe.talk` and `dev.roe.project`. + Refresh them from upstream when the shared defs change. - `pnpm lex:gen` regenerates the TypeScript in `shared/lex/` from these files. diff --git a/lexicons/id/sifa/defs.json b/lexicons/id/sifa/defs.json new file mode 100644 index 00000000..df2a1630 --- /dev/null +++ b/lexicons/id/sifa/defs.json @@ -0,0 +1,1060 @@ +{ + "lexicon": 1, + "id": "id.sifa.defs", + "description": "Shared type definitions for Sifa professional profile lexicons.", + "defs": { + "employmentType": { + "type": "string", + "description": "The type of employment arrangement.", + "knownValues": [ + "id.sifa.defs#fullTime", + "id.sifa.defs#partTime", + "id.sifa.defs#temporary", + "id.sifa.defs#seasonal", + "id.sifa.defs#contract", + "id.sifa.defs#freelance", + "id.sifa.defs#selfEmployed", + "id.sifa.defs#independentWork", + "id.sifa.defs#internship", + "id.sifa.defs#apprenticeship", + "id.sifa.defs#fellowship", + "id.sifa.defs#trainee", + "id.sifa.defs#volunteer", + "id.sifa.defs#boardMember", + "id.sifa.defs#boardObserver", + "id.sifa.defs#advisor" + ] + }, + "fullTime": { + "type": "token", + "description": "Full-time employee of the organization." + }, + "partTime": { + "type": "token", + "description": "Part-time employee of the organization." + }, + "temporary": { + "type": "token", + "description": "Fixed-end-date role as a direct employee of the organization." + }, + "seasonal": { + "type": "token", + "description": "Recurring role tied to a season or peak period." + }, + "contract": { + "type": "token", + "description": "Fixed-scope engagement as an independent contractor." + }, + "freelance": { + "type": "token", + "description": "Solo service provider working with multiple clients on a project basis. No employees." + }, + "selfEmployed": { + "type": "token", + "description": "Operating your own business or practice. May have employees." + }, + "independentWork": { + "type": "token", + "description": "Self-initiated, sustained work I lead — community building, content creation, ecosystem contribution, or similar. May involve a registered entity but does not pay me personally. Often run alongside other employment." + }, + "internship": { + "type": "token", + "description": "Structured early-career work experience, often tied to studies." + }, + "apprenticeship": { + "type": "token", + "description": "Formal training-to-certification program combining paid work and education." + }, + "fellowship": { + "type": "token", + "description": "Funded research, academic, or mission-driven position, typically selective." + }, + "trainee": { + "type": "token", + "description": "Structured early-career rotation or graduate program." + }, + "volunteer": { + "type": "token", + "description": "Volunteer work (when used as employment type)." + }, + "boardMember": { + "type": "token", + "description": "Seat on a board of directors or supervisory board, carrying a vote and fiduciary duty. Usually not employment, in the same way volunteer is not." + }, + "boardObserver": { + "type": "token", + "description": "Board observer seat: attends and is informed but holds no vote. The common shape of an investor seat, kept distinct so it does not read as directorship." + }, + "advisor": { + "type": "token", + "description": "Advisory role, paid or unpaid, without a board seat or line responsibility." + }, + + "workplaceType": { + "type": "string", + "description": "The workplace arrangement.", + "knownValues": [ + "id.sifa.defs#onSite", + "id.sifa.defs#remote", + "id.sifa.defs#hybrid", + "id.sifa.defs#remoteLocal", + "id.sifa.defs#remoteRegion", + "id.sifa.defs#remoteGlobal" + ] + }, + "onSite": { "type": "token", "description": "On-site/in-office work." }, + "remote": { + "type": "token", + "description": "Fully remote work (unspecified scope). Treated as remoteGlobal by AppViews. Prefer the scoped variants for new records." + }, + "hybrid": { "type": "token", "description": "Hybrid on-site and remote work." }, + "remoteLocal": { + "type": "token", + "description": "Remote work within the same country as the employer." + }, + "remoteRegion": { + "type": "token", + "description": "Remote work within the same timezone region or continent." + }, + "remoteGlobal": { + "type": "token", + "description": "Remote work from anywhere worldwide." + }, + + "industryType": { + "type": "string", + "description": "Professional industry sector.", + "knownValues": [ + "id.sifa.defs#industryTechnology", + "id.sifa.defs#industryFinance", + "id.sifa.defs#industryHealthcare", + "id.sifa.defs#industryEducation", + "id.sifa.defs#industryMedia", + "id.sifa.defs#industryRetail", + "id.sifa.defs#industryManufacturing", + "id.sifa.defs#industryEnergy", + "id.sifa.defs#industryGovernment", + "id.sifa.defs#industryLegal", + "id.sifa.defs#industryConsulting", + "id.sifa.defs#industryNonprofit", + "id.sifa.defs#industryRealEstate", + "id.sifa.defs#industryTransport", + "id.sifa.defs#industryAgriculture", + "id.sifa.defs#industryHospitality", + "id.sifa.defs#industryTelecom", + "id.sifa.defs#industryMining", + "id.sifa.defs#industryFashion", + "id.sifa.defs#industryMaritime", + "id.sifa.defs#industryOther" + ] + }, + "industryTechnology": { "type": "token", "description": "Technology." }, + "industryFinance": { "type": "token", "description": "Finance & Banking." }, + "industryHealthcare": { "type": "token", "description": "Healthcare & Life Sciences." }, + "industryEducation": { "type": "token", "description": "Education & Research." }, + "industryMedia": { "type": "token", "description": "Media & Entertainment." }, + "industryRetail": { "type": "token", "description": "Retail & E-commerce." }, + "industryManufacturing": { "type": "token", "description": "Manufacturing & Engineering." }, + "industryEnergy": { "type": "token", "description": "Energy & Environment." }, + "industryGovernment": { "type": "token", "description": "Government & Public Sector." }, + "industryLegal": { "type": "token", "description": "Legal." }, + "industryConsulting": { "type": "token", "description": "Consulting & Professional Services." }, + "industryNonprofit": { "type": "token", "description": "Non-profit & Social Impact." }, + "industryRealEstate": { "type": "token", "description": "Real Estate & Construction." }, + "industryTransport": { "type": "token", "description": "Transportation & Logistics." }, + "industryAgriculture": { "type": "token", "description": "Agriculture & Food." }, + "industryHospitality": { "type": "token", "description": "Hospitality & Tourism." }, + "industryTelecom": { "type": "token", "description": "Telecommunications." }, + "industryMining": { "type": "token", "description": "Mining & Resources." }, + "industryFashion": { "type": "token", "description": "Fashion & Textiles." }, + "industryMaritime": { "type": "token", "description": "Maritime & Shipping." }, + "industryOther": { "type": "token", "description": "Other industry." }, + + "domainType": { + "type": "string", + "description": "Professional domain within an industry. Optional refinement of industryType.", + "knownValues": [ + "id.sifa.defs#domainSoftwareEngineering", + "id.sifa.defs#domainDataScience", + "id.sifa.defs#domainCybersecurity", + "id.sifa.defs#domainDevops", + "id.sifa.defs#domainProductDesign", + "id.sifa.defs#domainGameDev", + "id.sifa.defs#domainBanking", + "id.sifa.defs#domainFintech", + "id.sifa.defs#domainInsurance", + "id.sifa.defs#domainInvestmentMgmt", + "id.sifa.defs#domainClinicalResearch", + "id.sifa.defs#domainHealthtech", + "id.sifa.defs#domainPharma", + "id.sifa.defs#domainHigherEd", + "id.sifa.defs#domainEdtech", + "id.sifa.defs#domainPrimarySecondary", + "id.sifa.defs#domainJournalism", + "id.sifa.defs#domainFilmVideo", + "id.sifa.defs#domainGaming", + "id.sifa.defs#domainAdvertising", + "id.sifa.defs#domainEcommerce", + "id.sifa.defs#domainSupplyChain", + "id.sifa.defs#domainAutomotive", + "id.sifa.defs#domainAerospace", + "id.sifa.defs#domainHardware", + "id.sifa.defs#domainRenewables", + "id.sifa.defs#domainOilGas", + "id.sifa.defs#domainClimateTech", + "id.sifa.defs#domainManagementConsulting", + "id.sifa.defs#domainDevrel", + "id.sifa.defs#domainHrRecruitment", + "id.sifa.defs#domainIpLaw", + "id.sifa.defs#domainCompliance", + "id.sifa.defs#domainHumanRights", + "id.sifa.defs#domainOpenSource", + "id.sifa.defs#domainPublicPolicy", + "id.sifa.defs#domainDefense", + "id.sifa.defs#domainProptech", + "id.sifa.defs#domainAutonomousVehicles", + "id.sifa.defs#domainLogistics", + "id.sifa.defs#domainAgritech", + "id.sifa.defs#domainFoodTech", + "id.sifa.defs#domainHotels", + "id.sifa.defs#domainTravelTourism", + "id.sifa.defs#domainFoodBeverage", + "id.sifa.defs#domainNetworkInfra", + "id.sifa.defs#domainMobileServices", + "id.sifa.defs#domainExtraction", + "id.sifa.defs#domainGeological", + "id.sifa.defs#domainFashionDesign", + "id.sifa.defs#domainTextileManufacturing", + "id.sifa.defs#domainShipping", + "id.sifa.defs#domainPortOperations", + "id.sifa.defs#domainNavalArchitecture" + ] + }, + "domainSoftwareEngineering": { "type": "token", "description": "Software Engineering." }, + "domainDataScience": { "type": "token", "description": "Data Science & ML." }, + "domainCybersecurity": { "type": "token", "description": "Cybersecurity." }, + "domainDevops": { "type": "token", "description": "DevOps & Infrastructure." }, + "domainProductDesign": { "type": "token", "description": "Product & UX Design." }, + "domainGameDev": { "type": "token", "description": "Game Development." }, + "domainBanking": { "type": "token", "description": "Banking." }, + "domainFintech": { "type": "token", "description": "Fintech." }, + "domainInsurance": { "type": "token", "description": "Insurance." }, + "domainInvestmentMgmt": { "type": "token", "description": "Investment Management." }, + "domainClinicalResearch": { "type": "token", "description": "Clinical Research." }, + "domainHealthtech": { "type": "token", "description": "Health Technology." }, + "domainPharma": { "type": "token", "description": "Pharmaceuticals." }, + "domainHigherEd": { "type": "token", "description": "Higher Education." }, + "domainEdtech": { "type": "token", "description": "Education Technology." }, + "domainPrimarySecondary": { "type": "token", "description": "Primary & Secondary Education." }, + "domainJournalism": { "type": "token", "description": "Journalism." }, + "domainFilmVideo": { "type": "token", "description": "Film & Video." }, + "domainGaming": { "type": "token", "description": "Gaming & Interactive Media." }, + "domainAdvertising": { "type": "token", "description": "Advertising & Marketing." }, + "domainEcommerce": { "type": "token", "description": "E-commerce." }, + "domainSupplyChain": { "type": "token", "description": "Supply Chain & Fulfillment." }, + "domainAutomotive": { "type": "token", "description": "Automotive." }, + "domainAerospace": { "type": "token", "description": "Aerospace & Defense." }, + "domainHardware": { "type": "token", "description": "Hardware & Electronics." }, + "domainRenewables": { "type": "token", "description": "Renewable Energy." }, + "domainOilGas": { "type": "token", "description": "Oil & Gas." }, + "domainClimateTech": { "type": "token", "description": "Climate Tech." }, + "domainManagementConsulting": { "type": "token", "description": "Management Consulting." }, + "domainDevrel": { "type": "token", "description": "Developer Relations." }, + "domainHrRecruitment": { "type": "token", "description": "HR & Recruitment." }, + "domainIpLaw": { "type": "token", "description": "Intellectual Property." }, + "domainCompliance": { "type": "token", "description": "Compliance & Regulatory." }, + "domainHumanRights": { "type": "token", "description": "Human Rights." }, + "domainOpenSource": { "type": "token", "description": "Open Source." }, + "domainPublicPolicy": { "type": "token", "description": "Public Policy." }, + "domainDefense": { "type": "token", "description": "Defense & Intelligence." }, + "domainProptech": { "type": "token", "description": "Property Technology." }, + "domainAutonomousVehicles": { "type": "token", "description": "Autonomous Vehicles." }, + "domainLogistics": { "type": "token", "description": "Logistics & Warehousing." }, + "domainAgritech": { "type": "token", "description": "Agricultural Technology." }, + "domainFoodTech": { "type": "token", "description": "Food Technology & Processing." }, + "domainHotels": { "type": "token", "description": "Hotels & Accommodation." }, + "domainTravelTourism": { "type": "token", "description": "Travel & Tourism." }, + "domainFoodBeverage": { "type": "token", "description": "Food & Beverage." }, + "domainNetworkInfra": { "type": "token", "description": "Network Infrastructure." }, + "domainMobileServices": { "type": "token", "description": "Mobile & Wireless Services." }, + "domainExtraction": { "type": "token", "description": "Extraction & Processing." }, + "domainGeological": { "type": "token", "description": "Geological Services." }, + "domainFashionDesign": { "type": "token", "description": "Fashion Design." }, + "domainTextileManufacturing": { "type": "token", "description": "Textile Manufacturing." }, + "domainShipping": { "type": "token", "description": "Shipping & Freight." }, + "domainPortOperations": { "type": "token", "description": "Port & Terminal Operations." }, + "domainNavalArchitecture": { + "type": "token", + "description": "Naval Architecture & Marine Engineering." + }, + + "industryDomain": { + "type": "object", + "description": "An industry/domain pair. Industry is required; domain is an optional refinement within the industry.", + "required": ["industry"], + "properties": { + "industry": { + "type": "string", + "description": "Professional industry sector token.", + "knownValues": [ + "id.sifa.defs#industryTechnology", + "id.sifa.defs#industryFinance", + "id.sifa.defs#industryHealthcare", + "id.sifa.defs#industryEducation", + "id.sifa.defs#industryMedia", + "id.sifa.defs#industryRetail", + "id.sifa.defs#industryManufacturing", + "id.sifa.defs#industryEnergy", + "id.sifa.defs#industryGovernment", + "id.sifa.defs#industryLegal", + "id.sifa.defs#industryConsulting", + "id.sifa.defs#industryNonprofit", + "id.sifa.defs#industryRealEstate", + "id.sifa.defs#industryTransport", + "id.sifa.defs#industryAgriculture", + "id.sifa.defs#industryHospitality", + "id.sifa.defs#industryTelecom", + "id.sifa.defs#industryMining", + "id.sifa.defs#industryFashion", + "id.sifa.defs#industryMaritime", + "id.sifa.defs#industryOther" + ] + }, + "domain": { + "type": "string", + "description": "Professional domain within the selected industry. Optional refinement.", + "knownValues": [ + "id.sifa.defs#domainSoftwareEngineering", + "id.sifa.defs#domainDataScience", + "id.sifa.defs#domainCybersecurity", + "id.sifa.defs#domainDevops", + "id.sifa.defs#domainProductDesign", + "id.sifa.defs#domainGameDev", + "id.sifa.defs#domainBanking", + "id.sifa.defs#domainFintech", + "id.sifa.defs#domainInsurance", + "id.sifa.defs#domainInvestmentMgmt", + "id.sifa.defs#domainClinicalResearch", + "id.sifa.defs#domainHealthtech", + "id.sifa.defs#domainPharma", + "id.sifa.defs#domainHigherEd", + "id.sifa.defs#domainEdtech", + "id.sifa.defs#domainPrimarySecondary", + "id.sifa.defs#domainJournalism", + "id.sifa.defs#domainFilmVideo", + "id.sifa.defs#domainGaming", + "id.sifa.defs#domainAdvertising", + "id.sifa.defs#domainEcommerce", + "id.sifa.defs#domainSupplyChain", + "id.sifa.defs#domainAutomotive", + "id.sifa.defs#domainAerospace", + "id.sifa.defs#domainHardware", + "id.sifa.defs#domainRenewables", + "id.sifa.defs#domainOilGas", + "id.sifa.defs#domainClimateTech", + "id.sifa.defs#domainManagementConsulting", + "id.sifa.defs#domainDevrel", + "id.sifa.defs#domainHrRecruitment", + "id.sifa.defs#domainIpLaw", + "id.sifa.defs#domainCompliance", + "id.sifa.defs#domainHumanRights", + "id.sifa.defs#domainOpenSource", + "id.sifa.defs#domainPublicPolicy", + "id.sifa.defs#domainDefense", + "id.sifa.defs#domainProptech", + "id.sifa.defs#domainAutonomousVehicles", + "id.sifa.defs#domainLogistics", + "id.sifa.defs#domainAgritech", + "id.sifa.defs#domainFoodTech", + "id.sifa.defs#domainHotels", + "id.sifa.defs#domainTravelTourism", + "id.sifa.defs#domainFoodBeverage", + "id.sifa.defs#domainNetworkInfra", + "id.sifa.defs#domainMobileServices", + "id.sifa.defs#domainExtraction", + "id.sifa.defs#domainGeological", + "id.sifa.defs#domainFashionDesign", + "id.sifa.defs#domainTextileManufacturing", + "id.sifa.defs#domainShipping", + "id.sifa.defs#domainPortOperations", + "id.sifa.defs#domainNavalArchitecture" + ] + } + } + }, + + "proficiency": { + "type": "string", + "description": "Language proficiency level. Maps to LinkedIn's five-level scale for lossless import.", + "knownValues": [ + "id.sifa.defs#elementary", + "id.sifa.defs#limitedWorking", + "id.sifa.defs#professionalWorking", + "id.sifa.defs#fullProfessional", + "id.sifa.defs#native" + ] + }, + "elementary": { "type": "token", "description": "Elementary proficiency." }, + "limitedWorking": { "type": "token", "description": "Limited working proficiency." }, + "professionalWorking": { "type": "token", "description": "Professional working proficiency." }, + "fullProfessional": { "type": "token", "description": "Full professional proficiency." }, + "native": { "type": "token", "description": "Native or bilingual proficiency." }, + + "skillCategory": { + "type": "string", + "description": "Broad category for grouping skills.", + "knownValues": [ + "id.sifa.defs#technical", + "id.sifa.defs#business", + "id.sifa.defs#creative", + "id.sifa.defs#interpersonal", + "id.sifa.defs#industry", + "id.sifa.defs#community", + "id.sifa.defs#security" + ] + }, + "technical": { "type": "token", "description": "Technical/engineering skills." }, + "business": { "type": "token", "description": "Business and management skills." }, + "creative": { "type": "token", "description": "Creative and design skills." }, + "interpersonal": { "type": "token", "description": "Interpersonal and communication skills." }, + "language": { + "type": "token", + "description": "Superseded. Language proficiency is its own record type, id.sifa.profile.language, so this is no longer offered as a skill category. Retained because removing a published token would break any consumer referencing it." + }, + "industry": { "type": "token", "description": "Industry-specific domain knowledge." }, + "community": { + "type": "token", + "description": "Community building and developer relations skills." + }, + "security": { "type": "token", "description": "Security and privacy skills." }, + + "openToWorkStatus": { + "type": "string", + "description": "The type of opportunity the user is open to.", + "knownValues": [ + "id.sifa.defs#fullTimeRoles", + "id.sifa.defs#partTimeRoles", + "id.sifa.defs#contractRoles", + "id.sifa.defs#commissions", + "id.sifa.defs#boardPositions", + "id.sifa.defs#mentoringOthers", + "id.sifa.defs#beingMentored", + "id.sifa.defs#collaborations", + "id.sifa.defs#speakingEngagements" + ] + }, + "fullTimeRoles": { + "type": "token", + "description": "Open to full-time employment opportunities." + }, + "partTimeRoles": { + "type": "token", + "description": "Open to part-time employment opportunities." + }, + "contractRoles": { + "type": "token", + "description": "Open to B2B contract or project-based freelance work, consulting, contract development." + }, + "commissions": { + "type": "token", + "description": "Open to commissioned creative work (illustration, design, voice work, music, etc.)." + }, + "boardPositions": { "type": "token", "description": "Open to advisory or board positions." }, + "mentoringOthers": { "type": "token", "description": "Open to mentoring others." }, + "beingMentored": { "type": "token", "description": "Open to being mentored." }, + "collaborations": { "type": "token", "description": "Open to project collaborations." }, + "speakingEngagements": { + "type": "token", + "description": "Open to speaking engagements (talks, panels, keynotes, workshops)." + }, + + "externalPlatform": { + "type": "string", + "description": "Platform type for an external account linked to a Sifa profile.", + "knownValues": [ + "id.sifa.defs#platformRss", + "id.sifa.defs#platformFediverse", + "id.sifa.defs#platformTwitter", + "id.sifa.defs#platformInstagram", + "id.sifa.defs#platformGithub", + "id.sifa.defs#platformCodeberg", + "id.sifa.defs#platformGitlab", + "id.sifa.defs#platformForgejo", + "id.sifa.defs#platformGitea", + "id.sifa.defs#platformYoutube", + "id.sifa.defs#platformLinkedin", + "id.sifa.defs#platformSubstack", + "id.sifa.defs#platformWebsite", + "id.sifa.defs#platformOrcid", + "id.sifa.defs#platformOther" + ] + }, + "platformRss": { + "type": "token", + "description": "RSS or Atom feed (blog, newsletter, podcast)." + }, + "platformFediverse": { + "type": "token", + "description": "Fediverse account (Mastodon, Misskey, Pleroma, etc.)." + }, + "platformTwitter": { "type": "token", "description": "Twitter/X account." }, + "platformInstagram": { "type": "token", "description": "Instagram account." }, + "platformGithub": { "type": "token", "description": "GitHub account." }, + "platformCodeberg": { "type": "token", "description": "Codeberg account." }, + "platformGitlab": { + "type": "token", + "description": "GitLab account (gitlab.com or self-hosted)." + }, + "platformForgejo": { + "type": "token", + "description": "Forgejo account on a self-hosted instance other than Codeberg." + }, + "platformGitea": { "type": "token", "description": "Gitea account on a self-hosted instance." }, + "platformYoutube": { "type": "token", "description": "YouTube channel." }, + "platformLinkedin": { "type": "token", "description": "LinkedIn profile." }, + "platformSubstack": { "type": "token", "description": "Substack newsletter." }, + "platformWebsite": { "type": "token", "description": "Personal or professional website." }, + "platformOrcid": { "type": "token", "description": "ORCID researcher identifier." }, + "platformOther": { + "type": "token", + "description": "Other platform not covered by specific tokens." + }, + + "locationType": { + "type": "string", + "description": "The role a location plays in a user's professional profile.", + "knownValues": [ + "id.sifa.defs#locationPrimary", + "id.sifa.defs#locationBusiness", + "id.sifa.defs#locationTravel" + ] + }, + "locationPrimary": { + "type": "token", + "description": "Primary residence or home location." + }, + "locationBusiness": { + "type": "token", + "description": "Business or operational location." + }, + "locationTravel": { + "type": "token", + "description": "Frequent travel or temporary location." + }, + + "skillRef": { + "type": "object", + "description": "A reference to an id.sifa.profile.skill record by AT-URI. No CID is required because skills are mutable records in the same user's repo.", + "required": ["uri"], + "properties": { + "uri": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the id.sifa.profile.skill record." + } + } + }, + + "agentRef": { + "type": "object", + "description": "A reference to an organization or person named by a record: a human label plus stable machine anchors. The name is a point-in-time snapshot captured when the record was saved; did and entityRef are the durable identity and should be resolved live. Consumers render the name, and follow did or entityRef to reach the current entity.", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "maxGraphemes": 256, + "maxLength": 2560, + "description": "Human-readable label for the organization or person, as it was known when the record was saved. A point-in-time snapshot, not refreshed from a lookup." + }, + "did": { + "type": "string", + "format": "did", + "description": "DID of the referenced organization or person's atproto account, if one exists. The stable identity: it survives handle and name changes." + }, + "entityRef": { + "type": "string", + "format": "uri", + "description": "Portable, app-neutral identifier for the referenced organization: a Wikidata Q-ID URI, a ROR URI, or an LEI URI, else a resolver URL. Enables deterministic resolution to a canonical entity even before the organization claims an atproto account. Absent for a bare person or a free-text entry." + } + } + }, + + "projectRole": { + "type": "string", + "description": "Role within a collaborative project.", + "knownValues": [ + "id.sifa.defs#projectOwner", + "id.sifa.defs#projectCore", + "id.sifa.defs#projectContributor" + ] + }, + "projectOwner": { + "type": "token", + "description": "Project owner with full management permissions. Multiple owners are supported." + }, + "projectCore": { + "type": "token", + "description": "Core team member with elevated involvement." + }, + "projectContributor": { + "type": "token", + "description": "Project contributor." + }, + + "projectStatus": { + "type": "string", + "description": "Current status of a collaborative project.", + "knownValues": [ + "id.sifa.defs#projectActive", + "id.sifa.defs#projectCompleted", + "id.sifa.defs#projectArchived" + ] + }, + "projectActive": { + "type": "token", + "description": "Project is actively maintained or in development." + }, + "projectCompleted": { + "type": "token", + "description": "Project has been completed." + }, + "projectArchived": { + "type": "token", + "description": "Project is archived and no longer active." + }, + + "confirmationRelation": { + "type": "string", + "description": "What an id.sifa.confirmation record affirms. Open set.", + "knownValues": [ + "id.sifa.defs#coSpeaker", + "id.sifa.defs#projectMember", + "id.sifa.defs#author", + "id.sifa.defs#collaborator", + "id.sifa.defs#colleague" + ] + }, + "coSpeaker": { + "type": "token", + "description": "The named person presented alongside the claimer at the referenced id.sifa.profile.presentationDelivery occasion." + }, + "projectMember": { + "type": "token", + "description": "The named person worked on the referenced id.sifa.profile.project." + }, + "author": { + "type": "token", + "description": "The named person co-authored the referenced id.sifa.profile.publication." + }, + "collaborator": { + "type": "token", + "description": "The named person worked alongside the claimer on the referenced id.sifa.profile.involvement." + }, + "colleague": { + "type": "token", + "description": "The confirming person worked with the owner of the referenced id.sifa.profile.position at the same organization. Unlike the other relations, the subject record names its owner rather than the confirming person. An organization account can write this too, but it stays a colleague-level confirmation: the organization-verified tier comes only from an id.sifa.org.employmentAttestation in the organization's own repository." + }, + "projectMemberRef": { + "type": "object", + "description": "Another person named as a member of a project. A claim by the record author, not a fact: it carries the named person's display name, avatar, and profile link only once they publish a matching id.sifa.confirmation.", + "required": ["did"], + "properties": { + "did": { + "type": "string", + "format": "did", + "description": "DID of the person named as a project member. Any atproto account is allowed." + }, + "role": { + "type": "string", + "description": "Role the named person held on the project. Display only: it grants no write access to the project record, which lives in the author's repository.", + "knownValues": [ + "id.sifa.defs#projectOwner", + "id.sifa.defs#projectCore", + "id.sifa.defs#projectContributor" + ] + }, + "title": { + "type": "string", + "maxGraphemes": 128, + "maxLength": 1280, + "description": "Optional title within the project (e.g. 'Lead Designer', 'Backend Engineer')." + } + } + }, + + "externalRecordRef": { + "type": "object", + "description": "A reference to a record in another repository or lexicon by AT-URI. The CID is optional: it pins a specific version as an integrity hint, but consumers should resolve the AT-URI live so the reference tracks edits to the target.", + "required": ["uri"], + "properties": { + "uri": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the referenced record." + }, + "cid": { + "type": "string", + "format": "cid", + "description": "Optional CID of a specific version of the referenced record. Used as an integrity hint only; live resolution is by AT-URI." + } + } + }, + + "presentationRole": { + "type": "string", + "description": "The user's role in a presentation or session. Open set.", + "knownValues": [ + "id.sifa.defs#presenter", + "id.sifa.defs#panelist", + "id.sifa.defs#keynote", + "id.sifa.defs#workshop", + "id.sifa.defs#host" + ] + }, + "relatedIdentifier": { + "type": "object", + "description": "A typed link from this work to another version or form of it, such as the published version of a preprint. Values mirror the DataCite relatedIdentifier vocabulary so they round-trip with DataCite and Crossref metadata.", + "required": ["identifier", "relationType"], + "properties": { + "identifier": { + "type": "string", + "maxLength": 2048, + "description": "The related work: a bare DOI (\"10.1234/example\"), an AT-URI of another record, or a URL, as named by identifierType." + }, + "identifierType": { + "type": "string", + "maxLength": 32, + "description": "Kind of identifier. Absent means DOI.", + "knownValues": ["DOI", "AT-URI", "URL"] + }, + "relationType": { + "type": "string", + "maxLength": 64, + "description": "How this work relates to the identified one, in DataCite relationType terms. For example IsPreprintOf on a preprint points at its published version.", + "knownValues": [ + "IsPreprintOf", + "HasPreprint", + "IsPublishedIn", + "IsVersionOf", + "HasVersion", + "IsNewVersionOf", + "IsPreviousVersionOf", + "IsIdenticalTo" + ] + } + } + }, + "presenter": { + "type": "token", + "description": "Delivered the session as the speaker or presenter (spoken or non-spoken)." + }, + "panelist": { "type": "token", "description": "Participated as a member of a panel." }, + "keynote": { "type": "token", "description": "Gave a keynote address." }, + "workshop": { "type": "token", "description": "Led or facilitated a workshop or tutorial." }, + "host": { + "type": "token", + "description": "Hosted or moderated the session, including acting as MC, moderator, or host of a podcast or livestream recorded there. Organizing the event itself is recorded as an id.sifa.profile.project whose events field references it, not as a delivery role." + }, + + "presentationLinkType": { + "type": "string", + "description": "The category of a related link on a presentation. Open set.", + "knownValues": [ + "id.sifa.defs#linkSlides", + "id.sifa.defs#linkRecording", + "id.sifa.defs#linkEvent", + "id.sifa.defs#linkRegistration", + "id.sifa.defs#linkWriteup", + "id.sifa.defs#linkOther" + ] + }, + "linkSlides": { "type": "token", "description": "Slides or presentation deck." }, + "linkRecording": { + "type": "token", + "description": "Video or audio recording of the presentation." + }, + "linkEvent": { "type": "token", "description": "The event or session page." }, + "linkRegistration": { "type": "token", "description": "Registration or ticket page." }, + "linkWriteup": { + "type": "token", + "description": "A long-form write-up, article, or transcript of the talk." + }, + "linkOther": { "type": "token", "description": "Other related link." }, + + "presentationLink": { + "type": "object", + "description": "A related link for a presentation or one of its deliveries.", + "required": ["uri"], + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "The link URL." + }, + "label": { + "type": "string", + "maxGraphemes": 64, + "maxLength": 640, + "description": "Optional display label (e.g., 'Watch recording', 'Slides')." + }, + "type": { + "type": "string", + "description": "Optional link category, used to pick an icon. Open set; see id.sifa.defs#presentationLinkType.", + "knownValues": [ + "id.sifa.defs#linkSlides", + "id.sifa.defs#linkRecording", + "id.sifa.defs#linkEvent", + "id.sifa.defs#linkRegistration", + "id.sifa.defs#linkWriteup", + "id.sifa.defs#linkOther" + ] + } + } + }, + + "involvementKind": { + "type": "string", + "description": "The nature of an involvement record.", + "knownValues": [ + "id.sifa.defs#involvementOpenSource", + "id.sifa.defs#involvementCommunity", + "id.sifa.defs#involvementCharity", + "id.sifa.defs#involvementCivic", + "id.sifa.defs#involvementOther" + ] + }, + "courseRole": { + "type": "string", + "description": "The user's role in a course: taking it, teaching it, or assisting with it.", + "knownValues": [ + "id.sifa.defs#courseTaken", + "id.sifa.defs#courseTaught", + "id.sifa.defs#courseTeachingAssistant" + ] + }, + "courseTaken": { "type": "token", "description": "The user took the course as a student." }, + "courseTaught": { + "type": "token", + "description": "The user taught the course as an instructor or lecturer." + }, + "courseTeachingAssistant": { + "type": "token", + "description": "The user assisted with teaching the course, for example as a teaching assistant." + }, + "involvementOpenSource": { + "type": "token", + "description": "Open-source contribution or maintainership." + }, + "involvementCommunity": { + "type": "token", + "description": "Community organizing, moderation, or meetup/event running." + }, + "involvementCharity": { + "type": "token", + "description": "Charitable or volunteer work for a cause or person." + }, + "involvementCivic": { + "type": "token", + "description": "Board membership, policy, advisory, or public-consultation work." + }, + "involvementOther": { + "type": "token", + "description": "Other uncompensated involvement." + }, + + "investmentRole": { + "type": "string", + "description": "How the capital went in. General partner is deliberately absent: running a fund is a role, recorded as an id.sifa.profile.position, and a partner's own commitment to their fund is a limitedPartner entry against that fund.", + "knownValues": [ + "id.sifa.defs#angelInvestment", + "id.sifa.defs#syndicateInvestment", + "id.sifa.defs#limitedPartner", + "id.sifa.defs#otherInvestment" + ] + }, + "angelInvestment": { + "type": "token", + "description": "Direct investment in the person's own name, with the person choosing the deal." + }, + "syndicateInvestment": { + "type": "token", + "description": "Investment in a deal led by someone else, made through a per-deal pooled vehicle." + }, + "limitedPartner": { + "type": "token", + "description": "Capital committed to a fund rather than to a company. The person does not choose the fund's deals, and the named entity is the fund itself." + }, + "otherInvestment": { + "type": "token", + "description": "A capital position that fits none of the above." + }, + + "investmentStage": { + "type": "string", + "description": "The company's funding stage at the time the investment was made, not its stage today.", + "knownValues": [ + "id.sifa.defs#stagePreSeed", + "id.sifa.defs#stageSeed", + "id.sifa.defs#stageSeriesA", + "id.sifa.defs#stageSeriesB", + "id.sifa.defs#stageSeriesCPlus", + "id.sifa.defs#stageGrowth", + "id.sifa.defs#stageSecondary", + "id.sifa.defs#stageOther" + ] + }, + "stagePreSeed": { "type": "token", "description": "Pre-seed round." }, + "stageSeed": { "type": "token", "description": "Seed round." }, + "stageSeriesA": { "type": "token", "description": "Series A round." }, + "stageSeriesB": { "type": "token", "description": "Series B round." }, + "stageSeriesCPlus": { "type": "token", "description": "Series C or later round." }, + "stageGrowth": { "type": "token", "description": "Growth or late-stage round." }, + "stageSecondary": { + "type": "token", + "description": "Purchase of existing shares from another holder rather than newly issued shares." + }, + "stageOther": { + "type": "token", + "description": "A stage that fits none of the above, including rounds that predate the standard naming." + }, + + "investmentStatus": { + "type": "string", + "description": "Where the position stands now. Recording a write-off is showing your work; Sifa never derives a hit rate or return from these values.", + "knownValues": [ + "id.sifa.defs#investmentActive", + "id.sifa.defs#investmentExited", + "id.sifa.defs#investmentWrittenOff", + "id.sifa.defs#investmentUndisclosed" + ] + }, + "investmentActive": { + "type": "token", + "description": "The position is still held." + }, + "investmentExited": { + "type": "token", + "description": "The position was realised through an acquisition, IPO, or secondary sale." + }, + "investmentWrittenOff": { + "type": "token", + "description": "The company failed or the position was written down to nothing." + }, + "investmentUndisclosed": { + "type": "token", + "description": "The person prefers not to say where the position stands." + }, + + "investmentAmount": { + "type": "object", + "description": "An optional, deliberately structured amount. Free text was rejected here because an unparseable money string is worse than no amount at all.", + "required": ["value", "currency"], + "properties": { + "value": { + "type": "integer", + "minimum": 0, + "description": "Amount in whole major currency units (euros, not cents). Cheque sizes are round numbers, and whole units avoid the ambiguity of a bare figure." + }, + "currency": { + "type": "string", + "minLength": 3, + "maxLength": 3, + "description": "ISO 4217 three-letter currency code, uppercase. Enforced at the app layer." + } + } + }, + + "artifactLink": { + "type": "object", + "description": "A public artifact proving a piece of work. Reusable across involvement, and later projects/publications.", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "URL of the artifact." + }, + "kind": { + "type": "string", + "description": "What this link points to.", + "knownValues": [ + "pull-request", + "issue", + "commit", + "review", + "release", + "talk", + "video", + "slides", + "article", + "thread", + "dataset", + "edit", + "other" + ] + }, + "label": { + "type": "string", + "maxGraphemes": 200, + "maxLength": 2000, + "description": "Optional human-readable label (e.g. 'Merged PR #1234: keep-alive support')." + } + } + }, + + "employmentStatus": { + "type": "string", + "description": "Whether an employment relationship is ongoing or has ended.", + "knownValues": ["id.sifa.defs#employmentCurrent", "id.sifa.defs#employmentPast"] + }, + "employmentCurrent": { + "type": "token", + "description": "The person currently holds the position." + }, + "employmentPast": { + "type": "token", + "description": "The person held the position in the past. An end date gives the period." + }, + + "verificationMethod": { + "type": "string", + "description": "How Sifa verified an employment: which evidence backs an id.sifa.verification.employment record.", + "knownValues": [ + "id.sifa.defs#verifiedByEmail", + "id.sifa.defs#verifiedByOrg", + "id.sifa.defs#verifiedByDirectory", + "id.sifa.defs#verifiedByPeer" + ] + }, + "verifiedByEmail": { + "type": "token", + "description": "The person proved control of a mailbox at a domain recognized for the employing organization. Time-limited: the issued record carries expiresAt while this is the only method." + }, + "verifiedByOrg": { + "type": "token", + "description": "The organization's own account wrote an id.sifa.org.employmentAttestation for the position." + }, + "verifiedByDirectory": { + "type": "token", + "description": "The organization's directory sync wrote the attestation on the organization's behalf." + }, + "verifiedByPeer": { + "type": "token", + "description": "Enough verified colleagues confirmed the position. Reserved: not published in the first version." + }, + + "attestationSource": { + "type": "string", + "description": "How an id.sifa.org.employmentAttestation came to be written. Absent means manual.", + "knownValues": ["id.sifa.defs#attestationManual", "id.sifa.defs#attestationDirectory"] + }, + "attestationManual": { + "type": "token", + "description": "An account holder of the organization confirmed the employment by hand." + }, + "attestationDirectory": { + "type": "token", + "description": "The organization's directory sync (for example SCIM) wrote the attestation." + } + } +} diff --git a/lexicons/id/sifa/profile/presentation.json b/lexicons/id/sifa/profile/presentation.json new file mode 100644 index 00000000..cd542a5d --- /dev/null +++ b/lexicons/id/sifa/profile/presentation.json @@ -0,0 +1,101 @@ +{ + "lexicon": 1, + "id": "id.sifa.profile.presentation", + "description": "A reusable presentation: the content a person presents (a talk, workshop, poster, or demo), independent of any single occasion on which it is delivered. Delivered at one or more id.sifa.profile.presentationDelivery occasions.", + "defs": { + "main": { + "type": "record", + "description": "Record representing a single reusable presentation (the content), distinct from the occasions on which it is delivered.", + "key": "tid", + "record": { + "type": "object", + "required": ["title", "createdAt"], + "properties": { + "title": { + "type": "string", + "minLength": 1, + "maxGraphemes": 300, + "maxLength": 3000, + "description": "Title of the presentation.", + "x-skos:exactMatch": ["dcterms:title", "schema:name"] + }, + "description": { + "type": "string", + "maxGraphemes": 5000, + "maxLength": 50000, + "description": "Description or abstract of the presentation.", + "x-skos:exactMatch": ["bibo:abstract", "schema:abstract"] + }, + "duration": { + "type": "ref", + "ref": "#duration", + "description": "Typical length of the presentation, a fixed value or a range, in minutes.", + "x-skos:narrowMatch": ["schema:timeRequired"], + "x-skos:note": "The lexicon models a range; schema:timeRequired is a single ISO 8601 duration." + }, + "intendedAudiences": { + "type": "array", + "maxLength": 20, + "items": { + "type": "string", + "maxGraphemes": 100, + "maxLength": 1000 + }, + "description": "Intended audiences for this presentation, open text (e.g. 'Engineering leaders', 'Beginners').", + "x-skos:closeMatch": ["schema:audience"] + }, + "links": { + "type": "array", + "maxLength": 20, + "items": { + "type": "ref", + "ref": "id.sifa.defs#presentationLink" + }, + "description": "Canonical links for this content, such as slides or a recording." + }, + "writeupRef": { + "type": "ref", + "ref": "id.sifa.defs#externalRecordRef", + "description": "Optional reference to a long-form write-up of this presentation (a pub.leaflet.document or site.standard.document holding video, transcript, or article).", + "x-skos:closeMatch": ["dcterms:isReferencedBy", "schema:subjectOf"] + }, + "coverImage": { + "type": "blob", + "accept": ["image/png", "image/jpeg", "image/webp"], + "maxSize": 2000000, + "description": "Optional cover image for the presentation. Rendered as the talk-page hero and OpenGraph image. Max 2 MB, PNG, JPEG, or WebP.", + "x-skos:exactMatch": ["schema:image", "foaf:depiction"] + }, + "isPrimary": { + "type": "boolean", + "description": "Whether this is the user's primary talk, surfaced in profile Highlights. Only reusable talks (not one-off sessions) may be primary." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "Client-declared timestamp when this record was originally created." + } + } + }, + "x-skos:closeMatch": ["bibo:Slideshow", "schema:PresentationDigitalDocument"], + "x-skos:note": "Neither term carries the \"reusable, deliverable more than once\" semantics of the Sifa record." + }, + "duration": { + "type": "object", + "description": "A presentation length in minutes: a fixed value (minMinutes only) or a range (minMinutes to maxMinutes).", + "required": ["minMinutes"], + "properties": { + "minMinutes": { + "type": "integer", + "minimum": 1, + "description": "Length in minutes, or the lower bound when the length is offered as a range." + }, + "maxMinutes": { + "type": "integer", + "minimum": 1, + "description": "Upper bound in minutes when the length is offered as a range. Omit for a fixed length." + } + } + } + } +} diff --git a/lexicons/id/sifa/profile/presentationDelivery.json b/lexicons/id/sifa/profile/presentationDelivery.json new file mode 100644 index 00000000..150a89c6 --- /dev/null +++ b/lexicons/id/sifa/profile/presentationDelivery.json @@ -0,0 +1,131 @@ +{ + "lexicon": 1, + "id": "id.sifa.profile.presentationDelivery", + "description": "An occasion on which a person delivered a presentation: a specific talk, panel, workshop, or demo at an event. References the reusable id.sifa.profile.presentation content and, optionally, the calendar event.", + "defs": { + "main": { + "type": "record", + "description": "Record representing a single occasion on which a presentation was delivered. This is the entry shown on a profile's activity timeline. At least one of presentationRef, title, or eventName is expected, enforced at the app layer.", + "key": "tid", + "record": { + "type": "object", + "required": ["createdAt"], + "properties": { + "presentationRef": { + "type": "ref", + "ref": "id.sifa.defs#externalRecordRef", + "description": "Optional reference to the id.sifa.profile.presentation (the content) delivered here. When set, title, duration, and audiences are taken from it.", + "x-skos:closeMatch": ["bibo:presentedAt", "schema:workPerformed"] + }, + "sameAs": { + "type": "ref", + "ref": "id.sifa.defs#externalRecordRef", + "description": "The same session as recorded on another person's profile. Set when you keep your own entry for work someone else has also recorded, so consumers can tell the two describe one thing rather than showing it twice. Each side stays its own record: the other person cannot edit yours, and yours does not change theirs. Resolve by AT-URI, since they will keep editing their copy." + }, + "title": { + "type": "string", + "maxGraphemes": 300, + "maxLength": 3000, + "description": "Fallback title for this delivery, used when no presentationRef is set.", + "x-skos:exactMatch": ["dcterms:title", "schema:name"] + }, + "role": { + "type": "string", + "maxGraphemes": 64, + "maxLength": 640, + "description": "The presenter's role in this delivery. Open set; see id.sifa.defs#presentationRole.", + "knownValues": [ + "id.sifa.defs#presenter", + "id.sifa.defs#panelist", + "id.sifa.defs#keynote", + "id.sifa.defs#workshop", + "id.sifa.defs#host" + ], + "x-skos:closeMatch": ["bibo:performer", "schema:performer"], + "x-skos:note": "No external vocabulary distinguishes presenter, panelist, keynote, workshop and host at this granularity." + }, + "eventName": { + "type": "string", + "maxGraphemes": 300, + "maxLength": 3000, + "description": "Name of the event or venue. On the linked branch, hydrated from the calendar event's name.", + "x-skos:closeMatch": ["schema:superEvent", "bibo:Conference"] + }, + "date": { + "type": "string", + "maxLength": 10, + "description": "Calendar date of this delivery as YYYY-MM-DD, or YYYY-MM or YYYY when the exact day or month is not known (no time). Future dates are allowed for upcoming deliveries. The shape is enforced at the app layer. On the linked branch, derived from the event's startsAt in the event's own offset, and always a full day.", + "x-skos:exactMatch": ["schema:startDate", "event:time"] + }, + "location": { + "type": "string", + "maxGraphemes": 256, + "maxLength": 2560, + "description": "Legacy free-text display location (city, country, or venue), retained for dual-read. Prefer the structured address field. On the linked branch, composed from the calendar event's structured locations." + }, + "address": { + "type": "ref", + "ref": "community.lexicon.location.address", + "description": "Structured delivery location. Sifa enforces ISO 3166-1 alpha-2 country codes at the app layer and surfaces country (for a flag) and locality (city); region, postalCode, and street are unused for deliveries. Takes precedence over the legacy location string when present.", + "x-skos:exactMatch": ["schema:location", "event:place"] + }, + "mode": { + "type": "string", + "description": "Whether this delivery was in person, virtual, or hybrid. Stores the full community.lexicon.calendar.event mode token; absent means in person.", + "knownValues": [ + "community.lexicon.calendar.event#inperson", + "community.lexicon.calendar.event#virtual", + "community.lexicon.calendar.event#hybrid" + ], + "x-skos:exactMatch": ["schema:eventAttendanceMode"], + "x-skos:note": "The community.lexicon.calendar.event known values are already one-to-one with the schema.org enumeration." + }, + "status": { + "type": "string", + "description": "Scheduling status of this delivery, typically hydrated from a linked calendar event. Stores the full community.lexicon.calendar.event status token. Consumers should surface cancelled and postponed states.", + "knownValues": [ + "community.lexicon.calendar.event#scheduled", + "community.lexicon.calendar.event#cancelled", + "community.lexicon.calendar.event#postponed", + "community.lexicon.calendar.event#rescheduled", + "community.lexicon.calendar.event#planned" + ], + "x-skos:exactMatch": ["schema:eventStatus"], + "x-skos:note": "As with mode, already one-to-one with the schema.org enumeration." + }, + "links": { + "type": "array", + "maxLength": 20, + "items": { + "type": "ref", + "ref": "id.sifa.defs#presentationLink" + }, + "description": "Links specific to this delivery, such as the recording of this occasion." + }, + "eventRef": { + "type": "ref", + "ref": "id.sifa.defs#externalRecordRef", + "description": "Optional reference to a community.lexicon.calendar.event for this occasion. Display fields are hydrated live from the target by AT-URI, with the stored fields as a fallback when the target is unavailable." + }, + "coSpeakers": { + "type": "array", + "maxLength": 20, + "items": { + "type": "string", + "format": "did" + }, + "description": "DIDs of co-speakers who presented alongside the author at this occasion. Any atproto account is allowed; hydrated to profile cards on read and linked to the co-speaker's Sifa profile.", + "x-skos:exactMatch": ["schema:performer"] + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "Client-declared timestamp when this record was originally created." + } + } + }, + "x-skos:closeMatch": ["schema:Event", "event:Event"], + "x-skos:note": "BIBO models this relation as bibo:Slideshow bibo:presentedAt event:Event." + } + } +} diff --git a/lexicons/id/sifa/profile/project.json b/lexicons/id/sifa/profile/project.json new file mode 100644 index 00000000..57e674e1 --- /dev/null +++ b/lexicons/id/sifa/profile/project.json @@ -0,0 +1,117 @@ +{ + "lexicon": 1, + "id": "id.sifa.profile.project", + "description": "A project the user has worked on.", + "defs": { + "main": { + "type": "record", + "description": "Record representing a single project.", + "key": "tid", + "record": { + "type": "object", + "required": ["name", "createdAt"], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxGraphemes": 256, + "maxLength": 2560, + "description": "Project name." + }, + "role": { + "type": "string", + "maxGraphemes": 256, + "maxLength": 2560, + "description": "The user's own role on the project (e.g. 'Maintainer', 'Core contributor', 'Project lead'). Roles of other people named on the project live on members." + }, + "description": { + "type": "string", + "maxGraphemes": 5000, + "maxLength": 50000, + "description": "Description of the project, the user's role, and outcomes." + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the project (website, repository, demo, etc.)." + }, + "projectRef": { + "type": "ref", + "ref": "com.atproto.repo.strongRef", + "description": "Reference to the first-class id.sifa.project.self record this personal entry corresponds to, when there is one. A composition link, not a peer one: for the same project recorded on someone else's profile, see sameAs." + }, + "position": { + "type": "ref", + "ref": "com.atproto.repo.strongRef", + "description": "Reference to the associated id.sifa.profile.position record, if applicable." + }, + "sameAs": { + "type": "ref", + "ref": "id.sifa.defs#externalRecordRef", + "description": "The same project as recorded on another person's profile. Set when you keep your own entry for work someone else has also recorded, so consumers can tell the two describe one thing rather than showing it twice. Each side stays its own record: the other person cannot edit yours, and yours does not change theirs. Resolve by AT-URI, since they will keep editing their copy." + }, + "members": { + "type": "array", + "maxLength": 50, + "items": { + "type": "ref", + "ref": "id.sifa.defs#projectMemberRef" + }, + "description": "Other people who worked on this project. Each entry is a claim by the record author and is not self-verifying: the named person supplies the other half by publishing an id.sifa.confirmation record whose subject is this record and whose relation is id.sifa.defs#projectMember. Until they do, consumers must render the entry without their display name, avatar, or profile link. Confirming never puts this record on the named person's profile: it lives in the author's repository and the author can rename it at any time. A named person who wants the project on their profile keeps their own id.sifa.profile.project record and points its projectRef here." + }, + "events": { + "type": "array", + "maxLength": 200, + "items": { + "type": "ref", + "ref": "#projectEvent" + }, + "description": "Event occurrences this project organized or hosted, for example every edition of a conference or every meetup of a series. Each entry should reference a distinct event; consumers ignore entries that don't resolve to a community.lexicon.calendar.event. A talk the user also gave at one of these events is a separate id.sifa.profile.presentationDelivery whose eventRef points at the same event.", + "x-skos:relatedMatch": ["schema:organizer"] + }, + "startedAt": { + "type": "string", + "description": "Project start date in YYYY-MM or YYYY-MM-DD format." + }, + "endedAt": { + "type": "string", + "description": "Project end date in YYYY-MM or YYYY-MM-DD format. Omit if ongoing." + }, + "labels": { + "type": "union", + "description": "Self-label values for this project record.", + "refs": ["com.atproto.label.defs#selfLabels"] + }, + "isPrimary": { + "type": "boolean", + "description": "Whether this is the user's primary ongoing project, surfaced in profile Highlights. Only ongoing entries may be primary." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "Client-declared timestamp when this record was originally created." + } + } + }, + "x-skos:exactMatch": ["schema:Project", "foaf:Project"] + }, + "projectEvent": { + "type": "object", + "description": "One event occurrence linked to a project.", + "required": ["event"], + "properties": { + "event": { + "type": "ref", + "ref": "id.sifa.defs#externalRecordRef", + "description": "Reference to the community.lexicon.calendar.event. Resolve by AT-URI; the CID is an optional integrity hint." + }, + "role": { + "type": "string", + "maxGraphemes": 64, + "maxLength": 640, + "description": "The user's role at this occurrence when it differs from the project's role (e.g. 'Organizer' for one edition, 'Host' for another). Omit to inherit project.role." + } + } + } + } +} diff --git a/modules/shared/tid.ts b/modules/shared/tid.ts index cba2c95a..579f3b71 100644 --- a/modules/shared/tid.ts +++ b/modules/shared/tid.ts @@ -33,5 +33,14 @@ export function tidFromDate (date: string | Date): string { return s32(micros, 11) + s32(CLOCK_ID, 2) } +/** The timestamp a TID encodes, as an ISO string. */ +export function dateFromTid (tid: string): string { + let micros = 0 + for (const char of tid.slice(0, 11)) { + micros = micros * 32 + S32_ALPHABET.indexOf(char) + } + return new Date(Math.floor(micros / MS_TO_MICROSECONDS)).toISOString() +} + /** Stable TID for the site's publication record, derived from the first commit date. */ export const publicationRkey = tidFromDate('2019-12-10T20:18:52.000Z') diff --git a/modules/sync/providers/index.ts b/modules/sync/providers/index.ts index 403eb081..a21fc94b 100644 --- a/modules/sync/providers/index.ts +++ b/modules/sync/providers/index.ts @@ -2,6 +2,7 @@ import { GithubStarsProvider } from './github-stars.ts' import { DevToProvider } from './dev-to.ts' import { GdeAdvocuProvider } from './gde-advocu.ts' import { StandardSiteProvider } from './standard-site.ts' +import { SifaProvider } from './sifa.ts' export interface SyncItem { title: string @@ -31,6 +32,7 @@ function createProviders (): SyncProvider[] { new DevToProvider(), new GdeAdvocuProvider(), new StandardSiteProvider(), + new SifaProvider(), ] } diff --git a/modules/sync/providers/sifa.ts b/modules/sync/providers/sifa.ts new file mode 100644 index 00000000..3417397d --- /dev/null +++ b/modules/sync/providers/sifa.ts @@ -0,0 +1,190 @@ +import type { CollectionSchema, RecordInput } from 'airspace' +import type { l } from '@atproto/lex-schema' + +import type { SyncItem, SyncOptions, SyncProvider } from './index.ts' +import type { ProjectRecord, TalkGroupRecord, TalkRecord } from '../../../shared/cms/records.ts' +import { rkeyFromUri } from '../../../shared/cms/talk-mapper.ts' +import { sifaCollections } from '../../../shared/sifa.ts' +import { useBuildAirspace, useBuildAirspaceWithSession } from '../../shared/airspace.ts' +import { dateFromTid } from '../../shared/tid.ts' + +type Presentation = RecordInput> +type Delivery = RecordInput> +type Project = RecordInput> +type PresentationLink = NonNullable[number] + +interface Source { + rkey: string + value: V +} + +/** `dev.roe.projectCategory` rkeys whose projects appear on Sifa. */ +export const SIFA_PROJECT_CATEGORIES = new Set([ + '3my6ffubo2225', // Frameworks + '3mtxxqxd7cr26', // Sites & web apps + '3mtxxqyu2rz26', // Libraries + '3mtxxr2ndsb26', // Tools +]) + +const VIRTUAL_LOCATIONS = new Set(['🌐', '🌍', '🌎', '🌏']) +const VIRTUAL_TYPES = new Set(['podcast', 'stream']) + +const REGIONS: Record = { + gbeng: 'England', + gbsct: 'Scotland', + gbwls: 'Wales', +} + +const REGIONAL_INDICATOR_A = 0x1F1E6 +const BLACK_FLAG = 0x1F3F4 +const TAG_BASE = 0xE0000 +const TAG_CANCEL = 0xE007F + +/** Parses a country or subdivision flag emoji into a structured address. */ +export function addressFromFlag (flag: string | undefined): Delivery['address'] { + if (!flag) return + const points = [...flag.replace(/\uFE0F/g, '')].map(c => c.codePointAt(0)!) + + if (points.length === 2 && points.every(p => p >= REGIONAL_INDICATOR_A && p < REGIONAL_INDICATOR_A + 26)) { + const country = String.fromCharCode(...points.map(p => p - REGIONAL_INDICATOR_A + 65)) + return { $type: 'community.lexicon.location.address', country } + } + + if (points[0] === BLACK_FLAG && points.at(-1) === TAG_CANCEL && points.length > 4) { + const tag = String.fromCharCode(...points.slice(1, -1).map(p => p - TAG_BASE)) + const region = REGIONS[tag] + return { + $type: 'community.lexicon.location.address', + country: tag.slice(0, 2).toUpperCase(), + ...(region ? { region } : {}), + } + } +} + +export function toPresentation ({ rkey, value }: Source): Presentation { + return { + title: value.title, + ...(value.description ? { description: value.description } : {}), + createdAt: (value.createdAt ?? dateFromTid(rkey)) as l.DatetimeString, + } +} + +/** + * @param presentationUris AT-URIs of the `id.sifa.profile.presentation` records being + * published, keyed by the rkey of the `dev.roe.talkGroup` each mirrors. + */ +export function toDelivery ({ rkey, value }: Source, presentationUris: Map): Delivery { + const isVirtual = VIRTUAL_TYPES.has(value.type) || VIRTUAL_LOCATIONS.has(value.location?.replace(/\uFE0F/g, '') ?? '') + const presentationUri = value.group && presentationUris.get(rkeyFromUri(value.group.uri)) + const address = isVirtual ? undefined : addressFromFlag(value.location) + const role = value.type === 'workshop' + ? 'id.sifa.defs#workshop' + : VIRTUAL_TYPES.has(value.type) ? undefined : 'id.sifa.defs#presenter' + + const links: PresentationLink[] = [] + if (value.video) links.push({ uri: value.video as l.UriString, type: 'id.sifa.defs#linkRecording' }) + if (value.slides) links.push({ uri: `https://roe.dev/slides/${value.slides}.pdf`, type: 'id.sifa.defs#linkSlides' }) + if (value.link) links.push({ uri: value.link as l.UriString, type: value.type === 'podcast' ? 'id.sifa.defs#linkRecording' : 'id.sifa.defs#linkEvent' }) + if (value.demo) links.push({ uri: value.demo as l.UriString, label: 'Demo', type: 'id.sifa.defs#linkOther' }) + if (value.repo) links.push({ uri: value.repo as l.UriString, label: 'Source code', type: 'id.sifa.defs#linkOther' }) + + return { + ...(presentationUri ? { presentationRef: { uri: presentationUri as l.AtUriString } } : {}), + ...(value.title ? { title: value.title } : {}), + eventName: value.source, + date: value.date.slice(0, 10), + ...(role ? { role } : {}), + ...(isVirtual ? { mode: 'community.lexicon.calendar.event#virtual' } : {}), + ...(address ? { address } : {}), + ...(links.length ? { links } : {}), + createdAt: (value.createdAt ?? dateFromTid(rkey)) as l.DatetimeString, + } +} + +export function toProject ({ rkey, value }: Source): Project { + const url = (value.links?.find(link => link.role === 'community.lexicon.app.defs#linkRoleWebsite') ?? value.links?.[0])?.uri + return { + name: value.name, + ...(value.description ? { description: value.description } : {}), + ...(url ? { url: url as l.UriString } : {}), + createdAt: (value.createdAt ?? dateFromTid(rkey)) as l.DatetimeString, + } +} + +interface MirrorTarget { + list: () => Promise> + put: (rkey: string, value: V) => Promise + delete: (rkey: string) => Promise +} + +/** + * Makes a collection hold exactly `desired`: writes records that are new or + * changed and deletes any other record in it. + */ +async function mirror (target: MirrorTarget, desired: Map) { + const existing = new Map((await target.list()).map(r => [r.rkey, r.value])) + let written = 0 + let deleted = 0 + + for (const [rkey, value] of desired) { + const current = existing.get(rkey) + if (current && stableJson({ ...current as object, $type: undefined }) === stableJson(value)) continue + await target.put(rkey, value) + written++ + } + + for (const rkey of existing.keys()) { + if (desired.has(rkey)) continue + await target.delete(rkey) + deleted++ + } + + return { written, deleted } +} + +function stableJson (value: unknown): string { + return JSON.stringify(value, (_key, v) => v && typeof v === 'object' && !Array.isArray(v) + ? Object.fromEntries(Object.entries(v).filter(([, x]) => x !== undefined).sort(([a], [b]) => a.localeCompare(b))) + : v) +} + +export class SifaProvider implements SyncProvider { + name = 'sifa' + + async sync (_items: SyncItem[], { dryRun }: SyncOptions): Promise { + const source = useBuildAirspace() + const [{ did }, talkGroups, talks, projects] = await Promise.all([ + source.identity(), + source.talkGroups.list(), + source.talks.list(), + source.projects.list(), + ]) + + if (!talks.length || !talkGroups.length || !projects.length) { + throw new Error(`refusing to mirror an empty source (${talks.length} talks, ${talkGroups.length} talk groups, ${projects.length} projects)`) + } + + const presentationUris = new Map(talkGroups.map(g => [g.rkey, `at://${did}/id.sifa.profile.presentation/${g.rkey}`])) + const presentations = new Map(talkGroups.map(g => [g.rkey, toPresentation(g)])) + const deliveries = new Map(talks.map(t => [t.rkey, toDelivery(t, presentationUris)])) + const sifaProjects = new Map(projects + .filter(p => SIFA_PROJECT_CATEGORIES.has(rkeyFromUri(p.value.category.uri))) + .map(p => [p.rkey, toProject(p)])) + + if (dryRun) { + console.info(`[sync:sifa] Would mirror ${presentations.size} presentations, ${deliveries.size} deliveries and ${sifaProjects.size} projects`) + return + } + + const airspace = await useBuildAirspaceWithSession(sifaCollections) + const results = { + presentations: await mirror(airspace.presentations as MirrorTarget, presentations), + deliveries: await mirror(airspace.deliveries as MirrorTarget, deliveries), + projects: await mirror(airspace.projects as MirrorTarget, sifaProjects), + } + + for (const [collection, { written, deleted }] of Object.entries(results)) { + console.info(`[sync:sifa] ${collection}: ${written} written, ${deleted} deleted`) + } + } +} diff --git a/shared/lex/id.ts b/shared/lex/id.ts new file mode 100644 index 00000000..eae320ab --- /dev/null +++ b/shared/lex/id.ts @@ -0,0 +1,5 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +export * as sifa from './id/sifa.ts' diff --git a/shared/lex/id/sifa.ts b/shared/lex/id/sifa.ts new file mode 100644 index 00000000..3c2a6144 --- /dev/null +++ b/shared/lex/id/sifa.ts @@ -0,0 +1,6 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +export * as defs from './sifa/defs.ts' +export * as profile from './sifa/profile.ts' diff --git a/shared/lex/id/sifa/defs.defs.ts b/shared/lex/id/sifa/defs.defs.ts new file mode 100644 index 00000000..81a7b96b --- /dev/null +++ b/shared/lex/id/sifa/defs.defs.ts @@ -0,0 +1,3771 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +import { l } from '@atproto/lex-schema' + +const $nsid = 'id.sifa.defs' + +type $nsid = typeof $nsid + +export { $nsid } + +/** The type of employment arrangement. */ +type EmploymentType = + | 'id.sifa.defs#fullTime' + | 'id.sifa.defs#partTime' + | 'id.sifa.defs#temporary' + | 'id.sifa.defs#seasonal' + | 'id.sifa.defs#contract' + | 'id.sifa.defs#freelance' + | 'id.sifa.defs#selfEmployed' + | 'id.sifa.defs#independentWork' + | 'id.sifa.defs#internship' + | 'id.sifa.defs#apprenticeship' + | 'id.sifa.defs#fellowship' + | 'id.sifa.defs#trainee' + | 'id.sifa.defs#volunteer' + | 'id.sifa.defs#boardMember' + | 'id.sifa.defs#boardObserver' + | 'id.sifa.defs#advisor' + | l.UnknownString + +export type { EmploymentType } + +/** The type of employment arrangement. */ +const employmentType = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#fullTime', + 'id.sifa.defs#partTime', + 'id.sifa.defs#temporary', + 'id.sifa.defs#seasonal', + 'id.sifa.defs#contract', + 'id.sifa.defs#freelance', + 'id.sifa.defs#selfEmployed', + 'id.sifa.defs#independentWork', + 'id.sifa.defs#internship', + 'id.sifa.defs#apprenticeship', + 'id.sifa.defs#fellowship', + 'id.sifa.defs#trainee', + 'id.sifa.defs#volunteer', + 'id.sifa.defs#boardMember', + 'id.sifa.defs#boardObserver', + 'id.sifa.defs#advisor', + ] +}>() + +export { employmentType } + +/** Full-time employee of the organization. */ +const fullTime = /*#__PURE__*/ l.token($nsid, 'fullTime') + +export { fullTime } + +/** Full-time employee of the organization. */ +const FullTime = /*#__PURE__*/ fullTime.value + +/** Full-time employee of the organization. */ +type FullTime = typeof FullTime + +export { FullTime } + +/** Part-time employee of the organization. */ +const partTime = /*#__PURE__*/ l.token($nsid, 'partTime') + +export { partTime } + +/** Part-time employee of the organization. */ +const PartTime = /*#__PURE__*/ partTime.value + +/** Part-time employee of the organization. */ +type PartTime = typeof PartTime + +export { PartTime } + +/** Fixed-end-date role as a direct employee of the organization. */ +const temporary = /*#__PURE__*/ l.token($nsid, 'temporary') + +export { temporary } + +/** Fixed-end-date role as a direct employee of the organization. */ +const Temporary = /*#__PURE__*/ temporary.value + +/** Fixed-end-date role as a direct employee of the organization. */ +type Temporary = typeof Temporary + +export { Temporary } + +/** Recurring role tied to a season or peak period. */ +const seasonal = /*#__PURE__*/ l.token($nsid, 'seasonal') + +export { seasonal } + +/** Recurring role tied to a season or peak period. */ +const Seasonal = /*#__PURE__*/ seasonal.value + +/** Recurring role tied to a season or peak period. */ +type Seasonal = typeof Seasonal + +export { Seasonal } + +/** Fixed-scope engagement as an independent contractor. */ +const contract = /*#__PURE__*/ l.token($nsid, 'contract') + +export { contract } + +/** Fixed-scope engagement as an independent contractor. */ +const Contract = /*#__PURE__*/ contract.value + +/** Fixed-scope engagement as an independent contractor. */ +type Contract = typeof Contract + +export { Contract } + +/** Solo service provider working with multiple clients on a project basis. No employees. */ +const freelance = /*#__PURE__*/ l.token($nsid, 'freelance') + +export { freelance } + +/** Solo service provider working with multiple clients on a project basis. No employees. */ +const Freelance = /*#__PURE__*/ freelance.value + +/** Solo service provider working with multiple clients on a project basis. No employees. */ +type Freelance = typeof Freelance + +export { Freelance } + +/** Operating your own business or practice. May have employees. */ +const selfEmployed = /*#__PURE__*/ l.token($nsid, 'selfEmployed') + +export { selfEmployed } + +/** Operating your own business or practice. May have employees. */ +const SelfEmployed = /*#__PURE__*/ selfEmployed.value + +/** Operating your own business or practice. May have employees. */ +type SelfEmployed = typeof SelfEmployed + +export { SelfEmployed } + +/** Self-initiated, sustained work I lead — community building, content creation, ecosystem contribution, or similar. May involve a registered entity but does not pay me personally. Often run alongside other employment. */ +const independentWork = /*#__PURE__*/ l.token($nsid, 'independentWork') + +export { independentWork } + +/** Self-initiated, sustained work I lead — community building, content creation, ecosystem contribution, or similar. May involve a registered entity but does not pay me personally. Often run alongside other employment. */ +const IndependentWork = /*#__PURE__*/ independentWork.value + +/** Self-initiated, sustained work I lead — community building, content creation, ecosystem contribution, or similar. May involve a registered entity but does not pay me personally. Often run alongside other employment. */ +type IndependentWork = typeof IndependentWork + +export { IndependentWork } + +/** Structured early-career work experience, often tied to studies. */ +const internship = /*#__PURE__*/ l.token($nsid, 'internship') + +export { internship } + +/** Structured early-career work experience, often tied to studies. */ +const Internship = /*#__PURE__*/ internship.value + +/** Structured early-career work experience, often tied to studies. */ +type Internship = typeof Internship + +export { Internship } + +/** Formal training-to-certification program combining paid work and education. */ +const apprenticeship = /*#__PURE__*/ l.token($nsid, 'apprenticeship') + +export { apprenticeship } + +/** Formal training-to-certification program combining paid work and education. */ +const Apprenticeship = /*#__PURE__*/ apprenticeship.value + +/** Formal training-to-certification program combining paid work and education. */ +type Apprenticeship = typeof Apprenticeship + +export { Apprenticeship } + +/** Funded research, academic, or mission-driven position, typically selective. */ +const fellowship = /*#__PURE__*/ l.token($nsid, 'fellowship') + +export { fellowship } + +/** Funded research, academic, or mission-driven position, typically selective. */ +const Fellowship = /*#__PURE__*/ fellowship.value + +/** Funded research, academic, or mission-driven position, typically selective. */ +type Fellowship = typeof Fellowship + +export { Fellowship } + +/** Structured early-career rotation or graduate program. */ +const trainee = /*#__PURE__*/ l.token($nsid, 'trainee') + +export { trainee } + +/** Structured early-career rotation or graduate program. */ +const Trainee = /*#__PURE__*/ trainee.value + +/** Structured early-career rotation or graduate program. */ +type Trainee = typeof Trainee + +export { Trainee } + +/** Volunteer work (when used as employment type). */ +const volunteer = /*#__PURE__*/ l.token($nsid, 'volunteer') + +export { volunteer } + +/** Volunteer work (when used as employment type). */ +const Volunteer = /*#__PURE__*/ volunteer.value + +/** Volunteer work (when used as employment type). */ +type Volunteer = typeof Volunteer + +export { Volunteer } + +/** Seat on a board of directors or supervisory board, carrying a vote and fiduciary duty. Usually not employment, in the same way volunteer is not. */ +const boardMember = /*#__PURE__*/ l.token($nsid, 'boardMember') + +export { boardMember } + +/** Seat on a board of directors or supervisory board, carrying a vote and fiduciary duty. Usually not employment, in the same way volunteer is not. */ +const BoardMember = /*#__PURE__*/ boardMember.value + +/** Seat on a board of directors or supervisory board, carrying a vote and fiduciary duty. Usually not employment, in the same way volunteer is not. */ +type BoardMember = typeof BoardMember + +export { BoardMember } + +/** Board observer seat: attends and is informed but holds no vote. The common shape of an investor seat, kept distinct so it does not read as directorship. */ +const boardObserver = /*#__PURE__*/ l.token($nsid, 'boardObserver') + +export { boardObserver } + +/** Board observer seat: attends and is informed but holds no vote. The common shape of an investor seat, kept distinct so it does not read as directorship. */ +const BoardObserver = /*#__PURE__*/ boardObserver.value + +/** Board observer seat: attends and is informed but holds no vote. The common shape of an investor seat, kept distinct so it does not read as directorship. */ +type BoardObserver = typeof BoardObserver + +export { BoardObserver } + +/** Advisory role, paid or unpaid, without a board seat or line responsibility. */ +const advisor = /*#__PURE__*/ l.token($nsid, 'advisor') + +export { advisor } + +/** Advisory role, paid or unpaid, without a board seat or line responsibility. */ +const Advisor = /*#__PURE__*/ advisor.value + +/** Advisory role, paid or unpaid, without a board seat or line responsibility. */ +type Advisor = typeof Advisor + +export { Advisor } + +/** The workplace arrangement. */ +type WorkplaceType = + | 'id.sifa.defs#onSite' + | 'id.sifa.defs#remote' + | 'id.sifa.defs#hybrid' + | 'id.sifa.defs#remoteLocal' + | 'id.sifa.defs#remoteRegion' + | 'id.sifa.defs#remoteGlobal' + | l.UnknownString + +export type { WorkplaceType } + +/** The workplace arrangement. */ +const workplaceType = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#onSite', + 'id.sifa.defs#remote', + 'id.sifa.defs#hybrid', + 'id.sifa.defs#remoteLocal', + 'id.sifa.defs#remoteRegion', + 'id.sifa.defs#remoteGlobal', + ] +}>() + +export { workplaceType } + +/** On-site/in-office work. */ +const onSite = /*#__PURE__*/ l.token($nsid, 'onSite') + +export { onSite } + +/** On-site/in-office work. */ +const OnSite = /*#__PURE__*/ onSite.value + +/** On-site/in-office work. */ +type OnSite = typeof OnSite + +export { OnSite } + +/** Fully remote work (unspecified scope). Treated as remoteGlobal by AppViews. Prefer the scoped variants for new records. */ +const remote = /*#__PURE__*/ l.token($nsid, 'remote') + +export { remote } + +/** Fully remote work (unspecified scope). Treated as remoteGlobal by AppViews. Prefer the scoped variants for new records. */ +const Remote = /*#__PURE__*/ remote.value + +/** Fully remote work (unspecified scope). Treated as remoteGlobal by AppViews. Prefer the scoped variants for new records. */ +type Remote = typeof Remote + +export { Remote } + +/** Hybrid on-site and remote work. */ +const hybrid = /*#__PURE__*/ l.token($nsid, 'hybrid') + +export { hybrid } + +/** Hybrid on-site and remote work. */ +const Hybrid = /*#__PURE__*/ hybrid.value + +/** Hybrid on-site and remote work. */ +type Hybrid = typeof Hybrid + +export { Hybrid } + +/** Remote work within the same country as the employer. */ +const remoteLocal = /*#__PURE__*/ l.token($nsid, 'remoteLocal') + +export { remoteLocal } + +/** Remote work within the same country as the employer. */ +const RemoteLocal = /*#__PURE__*/ remoteLocal.value + +/** Remote work within the same country as the employer. */ +type RemoteLocal = typeof RemoteLocal + +export { RemoteLocal } + +/** Remote work within the same timezone region or continent. */ +const remoteRegion = /*#__PURE__*/ l.token($nsid, 'remoteRegion') + +export { remoteRegion } + +/** Remote work within the same timezone region or continent. */ +const RemoteRegion = /*#__PURE__*/ remoteRegion.value + +/** Remote work within the same timezone region or continent. */ +type RemoteRegion = typeof RemoteRegion + +export { RemoteRegion } + +/** Remote work from anywhere worldwide. */ +const remoteGlobal = /*#__PURE__*/ l.token($nsid, 'remoteGlobal') + +export { remoteGlobal } + +/** Remote work from anywhere worldwide. */ +const RemoteGlobal = /*#__PURE__*/ remoteGlobal.value + +/** Remote work from anywhere worldwide. */ +type RemoteGlobal = typeof RemoteGlobal + +export { RemoteGlobal } + +/** Professional industry sector. */ +type IndustryType = + | 'id.sifa.defs#industryTechnology' + | 'id.sifa.defs#industryFinance' + | 'id.sifa.defs#industryHealthcare' + | 'id.sifa.defs#industryEducation' + | 'id.sifa.defs#industryMedia' + | 'id.sifa.defs#industryRetail' + | 'id.sifa.defs#industryManufacturing' + | 'id.sifa.defs#industryEnergy' + | 'id.sifa.defs#industryGovernment' + | 'id.sifa.defs#industryLegal' + | 'id.sifa.defs#industryConsulting' + | 'id.sifa.defs#industryNonprofit' + | 'id.sifa.defs#industryRealEstate' + | 'id.sifa.defs#industryTransport' + | 'id.sifa.defs#industryAgriculture' + | 'id.sifa.defs#industryHospitality' + | 'id.sifa.defs#industryTelecom' + | 'id.sifa.defs#industryMining' + | 'id.sifa.defs#industryFashion' + | 'id.sifa.defs#industryMaritime' + | 'id.sifa.defs#industryOther' + | l.UnknownString + +export type { IndustryType } + +/** Professional industry sector. */ +const industryType = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#industryTechnology', + 'id.sifa.defs#industryFinance', + 'id.sifa.defs#industryHealthcare', + 'id.sifa.defs#industryEducation', + 'id.sifa.defs#industryMedia', + 'id.sifa.defs#industryRetail', + 'id.sifa.defs#industryManufacturing', + 'id.sifa.defs#industryEnergy', + 'id.sifa.defs#industryGovernment', + 'id.sifa.defs#industryLegal', + 'id.sifa.defs#industryConsulting', + 'id.sifa.defs#industryNonprofit', + 'id.sifa.defs#industryRealEstate', + 'id.sifa.defs#industryTransport', + 'id.sifa.defs#industryAgriculture', + 'id.sifa.defs#industryHospitality', + 'id.sifa.defs#industryTelecom', + 'id.sifa.defs#industryMining', + 'id.sifa.defs#industryFashion', + 'id.sifa.defs#industryMaritime', + 'id.sifa.defs#industryOther', + ] +}>() + +export { industryType } + +/** Technology. */ +const industryTechnology = /*#__PURE__*/ l.token($nsid, 'industryTechnology') + +export { industryTechnology } + +/** Technology. */ +const IndustryTechnology = /*#__PURE__*/ industryTechnology.value + +/** Technology. */ +type IndustryTechnology = typeof IndustryTechnology + +export { IndustryTechnology } + +/** Finance & Banking. */ +const industryFinance = /*#__PURE__*/ l.token($nsid, 'industryFinance') + +export { industryFinance } + +/** Finance & Banking. */ +const IndustryFinance = /*#__PURE__*/ industryFinance.value + +/** Finance & Banking. */ +type IndustryFinance = typeof IndustryFinance + +export { IndustryFinance } + +/** Healthcare & Life Sciences. */ +const industryHealthcare = /*#__PURE__*/ l.token($nsid, 'industryHealthcare') + +export { industryHealthcare } + +/** Healthcare & Life Sciences. */ +const IndustryHealthcare = /*#__PURE__*/ industryHealthcare.value + +/** Healthcare & Life Sciences. */ +type IndustryHealthcare = typeof IndustryHealthcare + +export { IndustryHealthcare } + +/** Education & Research. */ +const industryEducation = /*#__PURE__*/ l.token($nsid, 'industryEducation') + +export { industryEducation } + +/** Education & Research. */ +const IndustryEducation = /*#__PURE__*/ industryEducation.value + +/** Education & Research. */ +type IndustryEducation = typeof IndustryEducation + +export { IndustryEducation } + +/** Media & Entertainment. */ +const industryMedia = /*#__PURE__*/ l.token($nsid, 'industryMedia') + +export { industryMedia } + +/** Media & Entertainment. */ +const IndustryMedia = /*#__PURE__*/ industryMedia.value + +/** Media & Entertainment. */ +type IndustryMedia = typeof IndustryMedia + +export { IndustryMedia } + +/** Retail & E-commerce. */ +const industryRetail = /*#__PURE__*/ l.token($nsid, 'industryRetail') + +export { industryRetail } + +/** Retail & E-commerce. */ +const IndustryRetail = /*#__PURE__*/ industryRetail.value + +/** Retail & E-commerce. */ +type IndustryRetail = typeof IndustryRetail + +export { IndustryRetail } + +/** Manufacturing & Engineering. */ +const industryManufacturing = /*#__PURE__*/ l.token( + $nsid, + 'industryManufacturing', +) + +export { industryManufacturing } + +/** Manufacturing & Engineering. */ +const IndustryManufacturing = /*#__PURE__*/ industryManufacturing.value + +/** Manufacturing & Engineering. */ +type IndustryManufacturing = typeof IndustryManufacturing + +export { IndustryManufacturing } + +/** Energy & Environment. */ +const industryEnergy = /*#__PURE__*/ l.token($nsid, 'industryEnergy') + +export { industryEnergy } + +/** Energy & Environment. */ +const IndustryEnergy = /*#__PURE__*/ industryEnergy.value + +/** Energy & Environment. */ +type IndustryEnergy = typeof IndustryEnergy + +export { IndustryEnergy } + +/** Government & Public Sector. */ +const industryGovernment = /*#__PURE__*/ l.token($nsid, 'industryGovernment') + +export { industryGovernment } + +/** Government & Public Sector. */ +const IndustryGovernment = /*#__PURE__*/ industryGovernment.value + +/** Government & Public Sector. */ +type IndustryGovernment = typeof IndustryGovernment + +export { IndustryGovernment } + +/** Legal. */ +const industryLegal = /*#__PURE__*/ l.token($nsid, 'industryLegal') + +export { industryLegal } + +/** Legal. */ +const IndustryLegal = /*#__PURE__*/ industryLegal.value + +/** Legal. */ +type IndustryLegal = typeof IndustryLegal + +export { IndustryLegal } + +/** Consulting & Professional Services. */ +const industryConsulting = /*#__PURE__*/ l.token($nsid, 'industryConsulting') + +export { industryConsulting } + +/** Consulting & Professional Services. */ +const IndustryConsulting = /*#__PURE__*/ industryConsulting.value + +/** Consulting & Professional Services. */ +type IndustryConsulting = typeof IndustryConsulting + +export { IndustryConsulting } + +/** Non-profit & Social Impact. */ +const industryNonprofit = /*#__PURE__*/ l.token($nsid, 'industryNonprofit') + +export { industryNonprofit } + +/** Non-profit & Social Impact. */ +const IndustryNonprofit = /*#__PURE__*/ industryNonprofit.value + +/** Non-profit & Social Impact. */ +type IndustryNonprofit = typeof IndustryNonprofit + +export { IndustryNonprofit } + +/** Real Estate & Construction. */ +const industryRealEstate = /*#__PURE__*/ l.token($nsid, 'industryRealEstate') + +export { industryRealEstate } + +/** Real Estate & Construction. */ +const IndustryRealEstate = /*#__PURE__*/ industryRealEstate.value + +/** Real Estate & Construction. */ +type IndustryRealEstate = typeof IndustryRealEstate + +export { IndustryRealEstate } + +/** Transportation & Logistics. */ +const industryTransport = /*#__PURE__*/ l.token($nsid, 'industryTransport') + +export { industryTransport } + +/** Transportation & Logistics. */ +const IndustryTransport = /*#__PURE__*/ industryTransport.value + +/** Transportation & Logistics. */ +type IndustryTransport = typeof IndustryTransport + +export { IndustryTransport } + +/** Agriculture & Food. */ +const industryAgriculture = /*#__PURE__*/ l.token($nsid, 'industryAgriculture') + +export { industryAgriculture } + +/** Agriculture & Food. */ +const IndustryAgriculture = /*#__PURE__*/ industryAgriculture.value + +/** Agriculture & Food. */ +type IndustryAgriculture = typeof IndustryAgriculture + +export { IndustryAgriculture } + +/** Hospitality & Tourism. */ +const industryHospitality = /*#__PURE__*/ l.token($nsid, 'industryHospitality') + +export { industryHospitality } + +/** Hospitality & Tourism. */ +const IndustryHospitality = /*#__PURE__*/ industryHospitality.value + +/** Hospitality & Tourism. */ +type IndustryHospitality = typeof IndustryHospitality + +export { IndustryHospitality } + +/** Telecommunications. */ +const industryTelecom = /*#__PURE__*/ l.token($nsid, 'industryTelecom') + +export { industryTelecom } + +/** Telecommunications. */ +const IndustryTelecom = /*#__PURE__*/ industryTelecom.value + +/** Telecommunications. */ +type IndustryTelecom = typeof IndustryTelecom + +export { IndustryTelecom } + +/** Mining & Resources. */ +const industryMining = /*#__PURE__*/ l.token($nsid, 'industryMining') + +export { industryMining } + +/** Mining & Resources. */ +const IndustryMining = /*#__PURE__*/ industryMining.value + +/** Mining & Resources. */ +type IndustryMining = typeof IndustryMining + +export { IndustryMining } + +/** Fashion & Textiles. */ +const industryFashion = /*#__PURE__*/ l.token($nsid, 'industryFashion') + +export { industryFashion } + +/** Fashion & Textiles. */ +const IndustryFashion = /*#__PURE__*/ industryFashion.value + +/** Fashion & Textiles. */ +type IndustryFashion = typeof IndustryFashion + +export { IndustryFashion } + +/** Maritime & Shipping. */ +const industryMaritime = /*#__PURE__*/ l.token($nsid, 'industryMaritime') + +export { industryMaritime } + +/** Maritime & Shipping. */ +const IndustryMaritime = /*#__PURE__*/ industryMaritime.value + +/** Maritime & Shipping. */ +type IndustryMaritime = typeof IndustryMaritime + +export { IndustryMaritime } + +/** Other industry. */ +const industryOther = /*#__PURE__*/ l.token($nsid, 'industryOther') + +export { industryOther } + +/** Other industry. */ +const IndustryOther = /*#__PURE__*/ industryOther.value + +/** Other industry. */ +type IndustryOther = typeof IndustryOther + +export { IndustryOther } + +/** Professional domain within an industry. Optional refinement of industryType. */ +type DomainType = + | 'id.sifa.defs#domainSoftwareEngineering' + | 'id.sifa.defs#domainDataScience' + | 'id.sifa.defs#domainCybersecurity' + | 'id.sifa.defs#domainDevops' + | 'id.sifa.defs#domainProductDesign' + | 'id.sifa.defs#domainGameDev' + | 'id.sifa.defs#domainBanking' + | 'id.sifa.defs#domainFintech' + | 'id.sifa.defs#domainInsurance' + | 'id.sifa.defs#domainInvestmentMgmt' + | 'id.sifa.defs#domainClinicalResearch' + | 'id.sifa.defs#domainHealthtech' + | 'id.sifa.defs#domainPharma' + | 'id.sifa.defs#domainHigherEd' + | 'id.sifa.defs#domainEdtech' + | 'id.sifa.defs#domainPrimarySecondary' + | 'id.sifa.defs#domainJournalism' + | 'id.sifa.defs#domainFilmVideo' + | 'id.sifa.defs#domainGaming' + | 'id.sifa.defs#domainAdvertising' + | 'id.sifa.defs#domainEcommerce' + | 'id.sifa.defs#domainSupplyChain' + | 'id.sifa.defs#domainAutomotive' + | 'id.sifa.defs#domainAerospace' + | 'id.sifa.defs#domainHardware' + | 'id.sifa.defs#domainRenewables' + | 'id.sifa.defs#domainOilGas' + | 'id.sifa.defs#domainClimateTech' + | 'id.sifa.defs#domainManagementConsulting' + | 'id.sifa.defs#domainDevrel' + | 'id.sifa.defs#domainHrRecruitment' + | 'id.sifa.defs#domainIpLaw' + | 'id.sifa.defs#domainCompliance' + | 'id.sifa.defs#domainHumanRights' + | 'id.sifa.defs#domainOpenSource' + | 'id.sifa.defs#domainPublicPolicy' + | 'id.sifa.defs#domainDefense' + | 'id.sifa.defs#domainProptech' + | 'id.sifa.defs#domainAutonomousVehicles' + | 'id.sifa.defs#domainLogistics' + | 'id.sifa.defs#domainAgritech' + | 'id.sifa.defs#domainFoodTech' + | 'id.sifa.defs#domainHotels' + | 'id.sifa.defs#domainTravelTourism' + | 'id.sifa.defs#domainFoodBeverage' + | 'id.sifa.defs#domainNetworkInfra' + | 'id.sifa.defs#domainMobileServices' + | 'id.sifa.defs#domainExtraction' + | 'id.sifa.defs#domainGeological' + | 'id.sifa.defs#domainFashionDesign' + | 'id.sifa.defs#domainTextileManufacturing' + | 'id.sifa.defs#domainShipping' + | 'id.sifa.defs#domainPortOperations' + | 'id.sifa.defs#domainNavalArchitecture' + | l.UnknownString + +export type { DomainType } + +/** Professional domain within an industry. Optional refinement of industryType. */ +const domainType = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#domainSoftwareEngineering', + 'id.sifa.defs#domainDataScience', + 'id.sifa.defs#domainCybersecurity', + 'id.sifa.defs#domainDevops', + 'id.sifa.defs#domainProductDesign', + 'id.sifa.defs#domainGameDev', + 'id.sifa.defs#domainBanking', + 'id.sifa.defs#domainFintech', + 'id.sifa.defs#domainInsurance', + 'id.sifa.defs#domainInvestmentMgmt', + 'id.sifa.defs#domainClinicalResearch', + 'id.sifa.defs#domainHealthtech', + 'id.sifa.defs#domainPharma', + 'id.sifa.defs#domainHigherEd', + 'id.sifa.defs#domainEdtech', + 'id.sifa.defs#domainPrimarySecondary', + 'id.sifa.defs#domainJournalism', + 'id.sifa.defs#domainFilmVideo', + 'id.sifa.defs#domainGaming', + 'id.sifa.defs#domainAdvertising', + 'id.sifa.defs#domainEcommerce', + 'id.sifa.defs#domainSupplyChain', + 'id.sifa.defs#domainAutomotive', + 'id.sifa.defs#domainAerospace', + 'id.sifa.defs#domainHardware', + 'id.sifa.defs#domainRenewables', + 'id.sifa.defs#domainOilGas', + 'id.sifa.defs#domainClimateTech', + 'id.sifa.defs#domainManagementConsulting', + 'id.sifa.defs#domainDevrel', + 'id.sifa.defs#domainHrRecruitment', + 'id.sifa.defs#domainIpLaw', + 'id.sifa.defs#domainCompliance', + 'id.sifa.defs#domainHumanRights', + 'id.sifa.defs#domainOpenSource', + 'id.sifa.defs#domainPublicPolicy', + 'id.sifa.defs#domainDefense', + 'id.sifa.defs#domainProptech', + 'id.sifa.defs#domainAutonomousVehicles', + 'id.sifa.defs#domainLogistics', + 'id.sifa.defs#domainAgritech', + 'id.sifa.defs#domainFoodTech', + 'id.sifa.defs#domainHotels', + 'id.sifa.defs#domainTravelTourism', + 'id.sifa.defs#domainFoodBeverage', + 'id.sifa.defs#domainNetworkInfra', + 'id.sifa.defs#domainMobileServices', + 'id.sifa.defs#domainExtraction', + 'id.sifa.defs#domainGeological', + 'id.sifa.defs#domainFashionDesign', + 'id.sifa.defs#domainTextileManufacturing', + 'id.sifa.defs#domainShipping', + 'id.sifa.defs#domainPortOperations', + 'id.sifa.defs#domainNavalArchitecture', + ] +}>() + +export { domainType } + +/** Software Engineering. */ +const domainSoftwareEngineering = /*#__PURE__*/ l.token( + $nsid, + 'domainSoftwareEngineering', +) + +export { domainSoftwareEngineering } + +/** Software Engineering. */ +const DomainSoftwareEngineering = /*#__PURE__*/ domainSoftwareEngineering.value + +/** Software Engineering. */ +type DomainSoftwareEngineering = typeof DomainSoftwareEngineering + +export { DomainSoftwareEngineering } + +/** Data Science & ML. */ +const domainDataScience = /*#__PURE__*/ l.token($nsid, 'domainDataScience') + +export { domainDataScience } + +/** Data Science & ML. */ +const DomainDataScience = /*#__PURE__*/ domainDataScience.value + +/** Data Science & ML. */ +type DomainDataScience = typeof DomainDataScience + +export { DomainDataScience } + +/** Cybersecurity. */ +const domainCybersecurity = /*#__PURE__*/ l.token($nsid, 'domainCybersecurity') + +export { domainCybersecurity } + +/** Cybersecurity. */ +const DomainCybersecurity = /*#__PURE__*/ domainCybersecurity.value + +/** Cybersecurity. */ +type DomainCybersecurity = typeof DomainCybersecurity + +export { DomainCybersecurity } + +/** DevOps & Infrastructure. */ +const domainDevops = /*#__PURE__*/ l.token($nsid, 'domainDevops') + +export { domainDevops } + +/** DevOps & Infrastructure. */ +const DomainDevops = /*#__PURE__*/ domainDevops.value + +/** DevOps & Infrastructure. */ +type DomainDevops = typeof DomainDevops + +export { DomainDevops } + +/** Product & UX Design. */ +const domainProductDesign = /*#__PURE__*/ l.token($nsid, 'domainProductDesign') + +export { domainProductDesign } + +/** Product & UX Design. */ +const DomainProductDesign = /*#__PURE__*/ domainProductDesign.value + +/** Product & UX Design. */ +type DomainProductDesign = typeof DomainProductDesign + +export { DomainProductDesign } + +/** Game Development. */ +const domainGameDev = /*#__PURE__*/ l.token($nsid, 'domainGameDev') + +export { domainGameDev } + +/** Game Development. */ +const DomainGameDev = /*#__PURE__*/ domainGameDev.value + +/** Game Development. */ +type DomainGameDev = typeof DomainGameDev + +export { DomainGameDev } + +/** Banking. */ +const domainBanking = /*#__PURE__*/ l.token($nsid, 'domainBanking') + +export { domainBanking } + +/** Banking. */ +const DomainBanking = /*#__PURE__*/ domainBanking.value + +/** Banking. */ +type DomainBanking = typeof DomainBanking + +export { DomainBanking } + +/** Fintech. */ +const domainFintech = /*#__PURE__*/ l.token($nsid, 'domainFintech') + +export { domainFintech } + +/** Fintech. */ +const DomainFintech = /*#__PURE__*/ domainFintech.value + +/** Fintech. */ +type DomainFintech = typeof DomainFintech + +export { DomainFintech } + +/** Insurance. */ +const domainInsurance = /*#__PURE__*/ l.token($nsid, 'domainInsurance') + +export { domainInsurance } + +/** Insurance. */ +const DomainInsurance = /*#__PURE__*/ domainInsurance.value + +/** Insurance. */ +type DomainInsurance = typeof DomainInsurance + +export { DomainInsurance } + +/** Investment Management. */ +const domainInvestmentMgmt = /*#__PURE__*/ l.token( + $nsid, + 'domainInvestmentMgmt', +) + +export { domainInvestmentMgmt } + +/** Investment Management. */ +const DomainInvestmentMgmt = /*#__PURE__*/ domainInvestmentMgmt.value + +/** Investment Management. */ +type DomainInvestmentMgmt = typeof DomainInvestmentMgmt + +export { DomainInvestmentMgmt } + +/** Clinical Research. */ +const domainClinicalResearch = /*#__PURE__*/ l.token( + $nsid, + 'domainClinicalResearch', +) + +export { domainClinicalResearch } + +/** Clinical Research. */ +const DomainClinicalResearch = /*#__PURE__*/ domainClinicalResearch.value + +/** Clinical Research. */ +type DomainClinicalResearch = typeof DomainClinicalResearch + +export { DomainClinicalResearch } + +/** Health Technology. */ +const domainHealthtech = /*#__PURE__*/ l.token($nsid, 'domainHealthtech') + +export { domainHealthtech } + +/** Health Technology. */ +const DomainHealthtech = /*#__PURE__*/ domainHealthtech.value + +/** Health Technology. */ +type DomainHealthtech = typeof DomainHealthtech + +export { DomainHealthtech } + +/** Pharmaceuticals. */ +const domainPharma = /*#__PURE__*/ l.token($nsid, 'domainPharma') + +export { domainPharma } + +/** Pharmaceuticals. */ +const DomainPharma = /*#__PURE__*/ domainPharma.value + +/** Pharmaceuticals. */ +type DomainPharma = typeof DomainPharma + +export { DomainPharma } + +/** Higher Education. */ +const domainHigherEd = /*#__PURE__*/ l.token($nsid, 'domainHigherEd') + +export { domainHigherEd } + +/** Higher Education. */ +const DomainHigherEd = /*#__PURE__*/ domainHigherEd.value + +/** Higher Education. */ +type DomainHigherEd = typeof DomainHigherEd + +export { DomainHigherEd } + +/** Education Technology. */ +const domainEdtech = /*#__PURE__*/ l.token($nsid, 'domainEdtech') + +export { domainEdtech } + +/** Education Technology. */ +const DomainEdtech = /*#__PURE__*/ domainEdtech.value + +/** Education Technology. */ +type DomainEdtech = typeof DomainEdtech + +export { DomainEdtech } + +/** Primary & Secondary Education. */ +const domainPrimarySecondary = /*#__PURE__*/ l.token( + $nsid, + 'domainPrimarySecondary', +) + +export { domainPrimarySecondary } + +/** Primary & Secondary Education. */ +const DomainPrimarySecondary = /*#__PURE__*/ domainPrimarySecondary.value + +/** Primary & Secondary Education. */ +type DomainPrimarySecondary = typeof DomainPrimarySecondary + +export { DomainPrimarySecondary } + +/** Journalism. */ +const domainJournalism = /*#__PURE__*/ l.token($nsid, 'domainJournalism') + +export { domainJournalism } + +/** Journalism. */ +const DomainJournalism = /*#__PURE__*/ domainJournalism.value + +/** Journalism. */ +type DomainJournalism = typeof DomainJournalism + +export { DomainJournalism } + +/** Film & Video. */ +const domainFilmVideo = /*#__PURE__*/ l.token($nsid, 'domainFilmVideo') + +export { domainFilmVideo } + +/** Film & Video. */ +const DomainFilmVideo = /*#__PURE__*/ domainFilmVideo.value + +/** Film & Video. */ +type DomainFilmVideo = typeof DomainFilmVideo + +export { DomainFilmVideo } + +/** Gaming & Interactive Media. */ +const domainGaming = /*#__PURE__*/ l.token($nsid, 'domainGaming') + +export { domainGaming } + +/** Gaming & Interactive Media. */ +const DomainGaming = /*#__PURE__*/ domainGaming.value + +/** Gaming & Interactive Media. */ +type DomainGaming = typeof DomainGaming + +export { DomainGaming } + +/** Advertising & Marketing. */ +const domainAdvertising = /*#__PURE__*/ l.token($nsid, 'domainAdvertising') + +export { domainAdvertising } + +/** Advertising & Marketing. */ +const DomainAdvertising = /*#__PURE__*/ domainAdvertising.value + +/** Advertising & Marketing. */ +type DomainAdvertising = typeof DomainAdvertising + +export { DomainAdvertising } + +/** E-commerce. */ +const domainEcommerce = /*#__PURE__*/ l.token($nsid, 'domainEcommerce') + +export { domainEcommerce } + +/** E-commerce. */ +const DomainEcommerce = /*#__PURE__*/ domainEcommerce.value + +/** E-commerce. */ +type DomainEcommerce = typeof DomainEcommerce + +export { DomainEcommerce } + +/** Supply Chain & Fulfillment. */ +const domainSupplyChain = /*#__PURE__*/ l.token($nsid, 'domainSupplyChain') + +export { domainSupplyChain } + +/** Supply Chain & Fulfillment. */ +const DomainSupplyChain = /*#__PURE__*/ domainSupplyChain.value + +/** Supply Chain & Fulfillment. */ +type DomainSupplyChain = typeof DomainSupplyChain + +export { DomainSupplyChain } + +/** Automotive. */ +const domainAutomotive = /*#__PURE__*/ l.token($nsid, 'domainAutomotive') + +export { domainAutomotive } + +/** Automotive. */ +const DomainAutomotive = /*#__PURE__*/ domainAutomotive.value + +/** Automotive. */ +type DomainAutomotive = typeof DomainAutomotive + +export { DomainAutomotive } + +/** Aerospace & Defense. */ +const domainAerospace = /*#__PURE__*/ l.token($nsid, 'domainAerospace') + +export { domainAerospace } + +/** Aerospace & Defense. */ +const DomainAerospace = /*#__PURE__*/ domainAerospace.value + +/** Aerospace & Defense. */ +type DomainAerospace = typeof DomainAerospace + +export { DomainAerospace } + +/** Hardware & Electronics. */ +const domainHardware = /*#__PURE__*/ l.token($nsid, 'domainHardware') + +export { domainHardware } + +/** Hardware & Electronics. */ +const DomainHardware = /*#__PURE__*/ domainHardware.value + +/** Hardware & Electronics. */ +type DomainHardware = typeof DomainHardware + +export { DomainHardware } + +/** Renewable Energy. */ +const domainRenewables = /*#__PURE__*/ l.token($nsid, 'domainRenewables') + +export { domainRenewables } + +/** Renewable Energy. */ +const DomainRenewables = /*#__PURE__*/ domainRenewables.value + +/** Renewable Energy. */ +type DomainRenewables = typeof DomainRenewables + +export { DomainRenewables } + +/** Oil & Gas. */ +const domainOilGas = /*#__PURE__*/ l.token($nsid, 'domainOilGas') + +export { domainOilGas } + +/** Oil & Gas. */ +const DomainOilGas = /*#__PURE__*/ domainOilGas.value + +/** Oil & Gas. */ +type DomainOilGas = typeof DomainOilGas + +export { DomainOilGas } + +/** Climate Tech. */ +const domainClimateTech = /*#__PURE__*/ l.token($nsid, 'domainClimateTech') + +export { domainClimateTech } + +/** Climate Tech. */ +const DomainClimateTech = /*#__PURE__*/ domainClimateTech.value + +/** Climate Tech. */ +type DomainClimateTech = typeof DomainClimateTech + +export { DomainClimateTech } + +/** Management Consulting. */ +const domainManagementConsulting = /*#__PURE__*/ l.token( + $nsid, + 'domainManagementConsulting', +) + +export { domainManagementConsulting } + +/** Management Consulting. */ +const DomainManagementConsulting = + /*#__PURE__*/ domainManagementConsulting.value + +/** Management Consulting. */ +type DomainManagementConsulting = typeof DomainManagementConsulting + +export { DomainManagementConsulting } + +/** Developer Relations. */ +const domainDevrel = /*#__PURE__*/ l.token($nsid, 'domainDevrel') + +export { domainDevrel } + +/** Developer Relations. */ +const DomainDevrel = /*#__PURE__*/ domainDevrel.value + +/** Developer Relations. */ +type DomainDevrel = typeof DomainDevrel + +export { DomainDevrel } + +/** HR & Recruitment. */ +const domainHrRecruitment = /*#__PURE__*/ l.token($nsid, 'domainHrRecruitment') + +export { domainHrRecruitment } + +/** HR & Recruitment. */ +const DomainHrRecruitment = /*#__PURE__*/ domainHrRecruitment.value + +/** HR & Recruitment. */ +type DomainHrRecruitment = typeof DomainHrRecruitment + +export { DomainHrRecruitment } + +/** Intellectual Property. */ +const domainIpLaw = /*#__PURE__*/ l.token($nsid, 'domainIpLaw') + +export { domainIpLaw } + +/** Intellectual Property. */ +const DomainIpLaw = /*#__PURE__*/ domainIpLaw.value + +/** Intellectual Property. */ +type DomainIpLaw = typeof DomainIpLaw + +export { DomainIpLaw } + +/** Compliance & Regulatory. */ +const domainCompliance = /*#__PURE__*/ l.token($nsid, 'domainCompliance') + +export { domainCompliance } + +/** Compliance & Regulatory. */ +const DomainCompliance = /*#__PURE__*/ domainCompliance.value + +/** Compliance & Regulatory. */ +type DomainCompliance = typeof DomainCompliance + +export { DomainCompliance } + +/** Human Rights. */ +const domainHumanRights = /*#__PURE__*/ l.token($nsid, 'domainHumanRights') + +export { domainHumanRights } + +/** Human Rights. */ +const DomainHumanRights = /*#__PURE__*/ domainHumanRights.value + +/** Human Rights. */ +type DomainHumanRights = typeof DomainHumanRights + +export { DomainHumanRights } + +/** Open Source. */ +const domainOpenSource = /*#__PURE__*/ l.token($nsid, 'domainOpenSource') + +export { domainOpenSource } + +/** Open Source. */ +const DomainOpenSource = /*#__PURE__*/ domainOpenSource.value + +/** Open Source. */ +type DomainOpenSource = typeof DomainOpenSource + +export { DomainOpenSource } + +/** Public Policy. */ +const domainPublicPolicy = /*#__PURE__*/ l.token($nsid, 'domainPublicPolicy') + +export { domainPublicPolicy } + +/** Public Policy. */ +const DomainPublicPolicy = /*#__PURE__*/ domainPublicPolicy.value + +/** Public Policy. */ +type DomainPublicPolicy = typeof DomainPublicPolicy + +export { DomainPublicPolicy } + +/** Defense & Intelligence. */ +const domainDefense = /*#__PURE__*/ l.token($nsid, 'domainDefense') + +export { domainDefense } + +/** Defense & Intelligence. */ +const DomainDefense = /*#__PURE__*/ domainDefense.value + +/** Defense & Intelligence. */ +type DomainDefense = typeof DomainDefense + +export { DomainDefense } + +/** Property Technology. */ +const domainProptech = /*#__PURE__*/ l.token($nsid, 'domainProptech') + +export { domainProptech } + +/** Property Technology. */ +const DomainProptech = /*#__PURE__*/ domainProptech.value + +/** Property Technology. */ +type DomainProptech = typeof DomainProptech + +export { DomainProptech } + +/** Autonomous Vehicles. */ +const domainAutonomousVehicles = /*#__PURE__*/ l.token( + $nsid, + 'domainAutonomousVehicles', +) + +export { domainAutonomousVehicles } + +/** Autonomous Vehicles. */ +const DomainAutonomousVehicles = /*#__PURE__*/ domainAutonomousVehicles.value + +/** Autonomous Vehicles. */ +type DomainAutonomousVehicles = typeof DomainAutonomousVehicles + +export { DomainAutonomousVehicles } + +/** Logistics & Warehousing. */ +const domainLogistics = /*#__PURE__*/ l.token($nsid, 'domainLogistics') + +export { domainLogistics } + +/** Logistics & Warehousing. */ +const DomainLogistics = /*#__PURE__*/ domainLogistics.value + +/** Logistics & Warehousing. */ +type DomainLogistics = typeof DomainLogistics + +export { DomainLogistics } + +/** Agricultural Technology. */ +const domainAgritech = /*#__PURE__*/ l.token($nsid, 'domainAgritech') + +export { domainAgritech } + +/** Agricultural Technology. */ +const DomainAgritech = /*#__PURE__*/ domainAgritech.value + +/** Agricultural Technology. */ +type DomainAgritech = typeof DomainAgritech + +export { DomainAgritech } + +/** Food Technology & Processing. */ +const domainFoodTech = /*#__PURE__*/ l.token($nsid, 'domainFoodTech') + +export { domainFoodTech } + +/** Food Technology & Processing. */ +const DomainFoodTech = /*#__PURE__*/ domainFoodTech.value + +/** Food Technology & Processing. */ +type DomainFoodTech = typeof DomainFoodTech + +export { DomainFoodTech } + +/** Hotels & Accommodation. */ +const domainHotels = /*#__PURE__*/ l.token($nsid, 'domainHotels') + +export { domainHotels } + +/** Hotels & Accommodation. */ +const DomainHotels = /*#__PURE__*/ domainHotels.value + +/** Hotels & Accommodation. */ +type DomainHotels = typeof DomainHotels + +export { DomainHotels } + +/** Travel & Tourism. */ +const domainTravelTourism = /*#__PURE__*/ l.token($nsid, 'domainTravelTourism') + +export { domainTravelTourism } + +/** Travel & Tourism. */ +const DomainTravelTourism = /*#__PURE__*/ domainTravelTourism.value + +/** Travel & Tourism. */ +type DomainTravelTourism = typeof DomainTravelTourism + +export { DomainTravelTourism } + +/** Food & Beverage. */ +const domainFoodBeverage = /*#__PURE__*/ l.token($nsid, 'domainFoodBeverage') + +export { domainFoodBeverage } + +/** Food & Beverage. */ +const DomainFoodBeverage = /*#__PURE__*/ domainFoodBeverage.value + +/** Food & Beverage. */ +type DomainFoodBeverage = typeof DomainFoodBeverage + +export { DomainFoodBeverage } + +/** Network Infrastructure. */ +const domainNetworkInfra = /*#__PURE__*/ l.token($nsid, 'domainNetworkInfra') + +export { domainNetworkInfra } + +/** Network Infrastructure. */ +const DomainNetworkInfra = /*#__PURE__*/ domainNetworkInfra.value + +/** Network Infrastructure. */ +type DomainNetworkInfra = typeof DomainNetworkInfra + +export { DomainNetworkInfra } + +/** Mobile & Wireless Services. */ +const domainMobileServices = /*#__PURE__*/ l.token( + $nsid, + 'domainMobileServices', +) + +export { domainMobileServices } + +/** Mobile & Wireless Services. */ +const DomainMobileServices = /*#__PURE__*/ domainMobileServices.value + +/** Mobile & Wireless Services. */ +type DomainMobileServices = typeof DomainMobileServices + +export { DomainMobileServices } + +/** Extraction & Processing. */ +const domainExtraction = /*#__PURE__*/ l.token($nsid, 'domainExtraction') + +export { domainExtraction } + +/** Extraction & Processing. */ +const DomainExtraction = /*#__PURE__*/ domainExtraction.value + +/** Extraction & Processing. */ +type DomainExtraction = typeof DomainExtraction + +export { DomainExtraction } + +/** Geological Services. */ +const domainGeological = /*#__PURE__*/ l.token($nsid, 'domainGeological') + +export { domainGeological } + +/** Geological Services. */ +const DomainGeological = /*#__PURE__*/ domainGeological.value + +/** Geological Services. */ +type DomainGeological = typeof DomainGeological + +export { DomainGeological } + +/** Fashion Design. */ +const domainFashionDesign = /*#__PURE__*/ l.token($nsid, 'domainFashionDesign') + +export { domainFashionDesign } + +/** Fashion Design. */ +const DomainFashionDesign = /*#__PURE__*/ domainFashionDesign.value + +/** Fashion Design. */ +type DomainFashionDesign = typeof DomainFashionDesign + +export { DomainFashionDesign } + +/** Textile Manufacturing. */ +const domainTextileManufacturing = /*#__PURE__*/ l.token( + $nsid, + 'domainTextileManufacturing', +) + +export { domainTextileManufacturing } + +/** Textile Manufacturing. */ +const DomainTextileManufacturing = + /*#__PURE__*/ domainTextileManufacturing.value + +/** Textile Manufacturing. */ +type DomainTextileManufacturing = typeof DomainTextileManufacturing + +export { DomainTextileManufacturing } + +/** Shipping & Freight. */ +const domainShipping = /*#__PURE__*/ l.token($nsid, 'domainShipping') + +export { domainShipping } + +/** Shipping & Freight. */ +const DomainShipping = /*#__PURE__*/ domainShipping.value + +/** Shipping & Freight. */ +type DomainShipping = typeof DomainShipping + +export { DomainShipping } + +/** Port & Terminal Operations. */ +const domainPortOperations = /*#__PURE__*/ l.token( + $nsid, + 'domainPortOperations', +) + +export { domainPortOperations } + +/** Port & Terminal Operations. */ +const DomainPortOperations = /*#__PURE__*/ domainPortOperations.value + +/** Port & Terminal Operations. */ +type DomainPortOperations = typeof DomainPortOperations + +export { DomainPortOperations } + +/** Naval Architecture & Marine Engineering. */ +const domainNavalArchitecture = /*#__PURE__*/ l.token( + $nsid, + 'domainNavalArchitecture', +) + +export { domainNavalArchitecture } + +/** Naval Architecture & Marine Engineering. */ +const DomainNavalArchitecture = /*#__PURE__*/ domainNavalArchitecture.value + +/** Naval Architecture & Marine Engineering. */ +type DomainNavalArchitecture = typeof DomainNavalArchitecture + +export { DomainNavalArchitecture } + +/** An industry/domain pair. Industry is required; domain is an optional refinement within the industry. */ +type IndustryDomain = { + $type?: 'id.sifa.defs#industryDomain' + + /** + * Professional industry sector token. + */ + industry: + | 'id.sifa.defs#industryTechnology' + | 'id.sifa.defs#industryFinance' + | 'id.sifa.defs#industryHealthcare' + | 'id.sifa.defs#industryEducation' + | 'id.sifa.defs#industryMedia' + | 'id.sifa.defs#industryRetail' + | 'id.sifa.defs#industryManufacturing' + | 'id.sifa.defs#industryEnergy' + | 'id.sifa.defs#industryGovernment' + | 'id.sifa.defs#industryLegal' + | 'id.sifa.defs#industryConsulting' + | 'id.sifa.defs#industryNonprofit' + | 'id.sifa.defs#industryRealEstate' + | 'id.sifa.defs#industryTransport' + | 'id.sifa.defs#industryAgriculture' + | 'id.sifa.defs#industryHospitality' + | 'id.sifa.defs#industryTelecom' + | 'id.sifa.defs#industryMining' + | 'id.sifa.defs#industryFashion' + | 'id.sifa.defs#industryMaritime' + | 'id.sifa.defs#industryOther' + | l.UnknownString + + /** + * Professional domain within the selected industry. Optional refinement. + */ + domain?: + | 'id.sifa.defs#domainSoftwareEngineering' + | 'id.sifa.defs#domainDataScience' + | 'id.sifa.defs#domainCybersecurity' + | 'id.sifa.defs#domainDevops' + | 'id.sifa.defs#domainProductDesign' + | 'id.sifa.defs#domainGameDev' + | 'id.sifa.defs#domainBanking' + | 'id.sifa.defs#domainFintech' + | 'id.sifa.defs#domainInsurance' + | 'id.sifa.defs#domainInvestmentMgmt' + | 'id.sifa.defs#domainClinicalResearch' + | 'id.sifa.defs#domainHealthtech' + | 'id.sifa.defs#domainPharma' + | 'id.sifa.defs#domainHigherEd' + | 'id.sifa.defs#domainEdtech' + | 'id.sifa.defs#domainPrimarySecondary' + | 'id.sifa.defs#domainJournalism' + | 'id.sifa.defs#domainFilmVideo' + | 'id.sifa.defs#domainGaming' + | 'id.sifa.defs#domainAdvertising' + | 'id.sifa.defs#domainEcommerce' + | 'id.sifa.defs#domainSupplyChain' + | 'id.sifa.defs#domainAutomotive' + | 'id.sifa.defs#domainAerospace' + | 'id.sifa.defs#domainHardware' + | 'id.sifa.defs#domainRenewables' + | 'id.sifa.defs#domainOilGas' + | 'id.sifa.defs#domainClimateTech' + | 'id.sifa.defs#domainManagementConsulting' + | 'id.sifa.defs#domainDevrel' + | 'id.sifa.defs#domainHrRecruitment' + | 'id.sifa.defs#domainIpLaw' + | 'id.sifa.defs#domainCompliance' + | 'id.sifa.defs#domainHumanRights' + | 'id.sifa.defs#domainOpenSource' + | 'id.sifa.defs#domainPublicPolicy' + | 'id.sifa.defs#domainDefense' + | 'id.sifa.defs#domainProptech' + | 'id.sifa.defs#domainAutonomousVehicles' + | 'id.sifa.defs#domainLogistics' + | 'id.sifa.defs#domainAgritech' + | 'id.sifa.defs#domainFoodTech' + | 'id.sifa.defs#domainHotels' + | 'id.sifa.defs#domainTravelTourism' + | 'id.sifa.defs#domainFoodBeverage' + | 'id.sifa.defs#domainNetworkInfra' + | 'id.sifa.defs#domainMobileServices' + | 'id.sifa.defs#domainExtraction' + | 'id.sifa.defs#domainGeological' + | 'id.sifa.defs#domainFashionDesign' + | 'id.sifa.defs#domainTextileManufacturing' + | 'id.sifa.defs#domainShipping' + | 'id.sifa.defs#domainPortOperations' + | 'id.sifa.defs#domainNavalArchitecture' + | l.UnknownString +} + +export type { IndustryDomain } + +/** An industry/domain pair. Industry is required; domain is an optional refinement within the industry. */ +const industryDomain = /*#__PURE__*/ l.typedObject( + $nsid, + 'industryDomain', + /*#__PURE__*/ l.object({ + industry: /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#industryTechnology', + 'id.sifa.defs#industryFinance', + 'id.sifa.defs#industryHealthcare', + 'id.sifa.defs#industryEducation', + 'id.sifa.defs#industryMedia', + 'id.sifa.defs#industryRetail', + 'id.sifa.defs#industryManufacturing', + 'id.sifa.defs#industryEnergy', + 'id.sifa.defs#industryGovernment', + 'id.sifa.defs#industryLegal', + 'id.sifa.defs#industryConsulting', + 'id.sifa.defs#industryNonprofit', + 'id.sifa.defs#industryRealEstate', + 'id.sifa.defs#industryTransport', + 'id.sifa.defs#industryAgriculture', + 'id.sifa.defs#industryHospitality', + 'id.sifa.defs#industryTelecom', + 'id.sifa.defs#industryMining', + 'id.sifa.defs#industryFashion', + 'id.sifa.defs#industryMaritime', + 'id.sifa.defs#industryOther', + ] + }>(), + domain: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#domainSoftwareEngineering', + 'id.sifa.defs#domainDataScience', + 'id.sifa.defs#domainCybersecurity', + 'id.sifa.defs#domainDevops', + 'id.sifa.defs#domainProductDesign', + 'id.sifa.defs#domainGameDev', + 'id.sifa.defs#domainBanking', + 'id.sifa.defs#domainFintech', + 'id.sifa.defs#domainInsurance', + 'id.sifa.defs#domainInvestmentMgmt', + 'id.sifa.defs#domainClinicalResearch', + 'id.sifa.defs#domainHealthtech', + 'id.sifa.defs#domainPharma', + 'id.sifa.defs#domainHigherEd', + 'id.sifa.defs#domainEdtech', + 'id.sifa.defs#domainPrimarySecondary', + 'id.sifa.defs#domainJournalism', + 'id.sifa.defs#domainFilmVideo', + 'id.sifa.defs#domainGaming', + 'id.sifa.defs#domainAdvertising', + 'id.sifa.defs#domainEcommerce', + 'id.sifa.defs#domainSupplyChain', + 'id.sifa.defs#domainAutomotive', + 'id.sifa.defs#domainAerospace', + 'id.sifa.defs#domainHardware', + 'id.sifa.defs#domainRenewables', + 'id.sifa.defs#domainOilGas', + 'id.sifa.defs#domainClimateTech', + 'id.sifa.defs#domainManagementConsulting', + 'id.sifa.defs#domainDevrel', + 'id.sifa.defs#domainHrRecruitment', + 'id.sifa.defs#domainIpLaw', + 'id.sifa.defs#domainCompliance', + 'id.sifa.defs#domainHumanRights', + 'id.sifa.defs#domainOpenSource', + 'id.sifa.defs#domainPublicPolicy', + 'id.sifa.defs#domainDefense', + 'id.sifa.defs#domainProptech', + 'id.sifa.defs#domainAutonomousVehicles', + 'id.sifa.defs#domainLogistics', + 'id.sifa.defs#domainAgritech', + 'id.sifa.defs#domainFoodTech', + 'id.sifa.defs#domainHotels', + 'id.sifa.defs#domainTravelTourism', + 'id.sifa.defs#domainFoodBeverage', + 'id.sifa.defs#domainNetworkInfra', + 'id.sifa.defs#domainMobileServices', + 'id.sifa.defs#domainExtraction', + 'id.sifa.defs#domainGeological', + 'id.sifa.defs#domainFashionDesign', + 'id.sifa.defs#domainTextileManufacturing', + 'id.sifa.defs#domainShipping', + 'id.sifa.defs#domainPortOperations', + 'id.sifa.defs#domainNavalArchitecture', + ] + }>(), + ), + }), +) + +export { industryDomain } + +/** Language proficiency level. Maps to LinkedIn's five-level scale for lossless import. */ +type Proficiency = + | 'id.sifa.defs#elementary' + | 'id.sifa.defs#limitedWorking' + | 'id.sifa.defs#professionalWorking' + | 'id.sifa.defs#fullProfessional' + | 'id.sifa.defs#native' + | l.UnknownString + +export type { Proficiency } + +/** Language proficiency level. Maps to LinkedIn's five-level scale for lossless import. */ +const proficiency = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#elementary', + 'id.sifa.defs#limitedWorking', + 'id.sifa.defs#professionalWorking', + 'id.sifa.defs#fullProfessional', + 'id.sifa.defs#native', + ] +}>() + +export { proficiency } + +/** Elementary proficiency. */ +const elementary = /*#__PURE__*/ l.token($nsid, 'elementary') + +export { elementary } + +/** Elementary proficiency. */ +const Elementary = /*#__PURE__*/ elementary.value + +/** Elementary proficiency. */ +type Elementary = typeof Elementary + +export { Elementary } + +/** Limited working proficiency. */ +const limitedWorking = /*#__PURE__*/ l.token($nsid, 'limitedWorking') + +export { limitedWorking } + +/** Limited working proficiency. */ +const LimitedWorking = /*#__PURE__*/ limitedWorking.value + +/** Limited working proficiency. */ +type LimitedWorking = typeof LimitedWorking + +export { LimitedWorking } + +/** Professional working proficiency. */ +const professionalWorking = /*#__PURE__*/ l.token($nsid, 'professionalWorking') + +export { professionalWorking } + +/** Professional working proficiency. */ +const ProfessionalWorking = /*#__PURE__*/ professionalWorking.value + +/** Professional working proficiency. */ +type ProfessionalWorking = typeof ProfessionalWorking + +export { ProfessionalWorking } + +/** Full professional proficiency. */ +const fullProfessional = /*#__PURE__*/ l.token($nsid, 'fullProfessional') + +export { fullProfessional } + +/** Full professional proficiency. */ +const FullProfessional = /*#__PURE__*/ fullProfessional.value + +/** Full professional proficiency. */ +type FullProfessional = typeof FullProfessional + +export { FullProfessional } + +/** Native or bilingual proficiency. */ +const native$0 = /*#__PURE__*/ l.token($nsid, 'native') + +export { native$0 as 'native' } + +/** Native or bilingual proficiency. */ +const Native = /*#__PURE__*/ native$0.value + +/** Native or bilingual proficiency. */ +type Native = typeof Native + +export { Native } + +/** Broad category for grouping skills. */ +type SkillCategory = + | 'id.sifa.defs#technical' + | 'id.sifa.defs#business' + | 'id.sifa.defs#creative' + | 'id.sifa.defs#interpersonal' + | 'id.sifa.defs#industry' + | 'id.sifa.defs#community' + | 'id.sifa.defs#security' + | l.UnknownString + +export type { SkillCategory } + +/** Broad category for grouping skills. */ +const skillCategory = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#technical', + 'id.sifa.defs#business', + 'id.sifa.defs#creative', + 'id.sifa.defs#interpersonal', + 'id.sifa.defs#industry', + 'id.sifa.defs#community', + 'id.sifa.defs#security', + ] +}>() + +export { skillCategory } + +/** Technical/engineering skills. */ +const technical = /*#__PURE__*/ l.token($nsid, 'technical') + +export { technical } + +/** Technical/engineering skills. */ +const Technical = /*#__PURE__*/ technical.value + +/** Technical/engineering skills. */ +type Technical = typeof Technical + +export { Technical } + +/** Business and management skills. */ +const business = /*#__PURE__*/ l.token($nsid, 'business') + +export { business } + +/** Business and management skills. */ +const Business = /*#__PURE__*/ business.value + +/** Business and management skills. */ +type Business = typeof Business + +export { Business } + +/** Creative and design skills. */ +const creative = /*#__PURE__*/ l.token($nsid, 'creative') + +export { creative } + +/** Creative and design skills. */ +const Creative = /*#__PURE__*/ creative.value + +/** Creative and design skills. */ +type Creative = typeof Creative + +export { Creative } + +/** Interpersonal and communication skills. */ +const interpersonal = /*#__PURE__*/ l.token($nsid, 'interpersonal') + +export { interpersonal } + +/** Interpersonal and communication skills. */ +const Interpersonal = /*#__PURE__*/ interpersonal.value + +/** Interpersonal and communication skills. */ +type Interpersonal = typeof Interpersonal + +export { Interpersonal } + +/** Superseded. Language proficiency is its own record type, id.sifa.profile.language, so this is no longer offered as a skill category. Retained because removing a published token would break any consumer referencing it. */ +const language = /*#__PURE__*/ l.token($nsid, 'language') + +export { language } + +/** Superseded. Language proficiency is its own record type, id.sifa.profile.language, so this is no longer offered as a skill category. Retained because removing a published token would break any consumer referencing it. */ +const Language = /*#__PURE__*/ language.value + +/** Superseded. Language proficiency is its own record type, id.sifa.profile.language, so this is no longer offered as a skill category. Retained because removing a published token would break any consumer referencing it. */ +type Language = typeof Language + +export { Language } + +/** Industry-specific domain knowledge. */ +const industry = /*#__PURE__*/ l.token($nsid, 'industry') + +export { industry } + +/** Industry-specific domain knowledge. */ +const Industry = /*#__PURE__*/ industry.value + +/** Industry-specific domain knowledge. */ +type Industry = typeof Industry + +export { Industry } + +/** Community building and developer relations skills. */ +const community = /*#__PURE__*/ l.token($nsid, 'community') + +export { community } + +/** Community building and developer relations skills. */ +const Community = /*#__PURE__*/ community.value + +/** Community building and developer relations skills. */ +type Community = typeof Community + +export { Community } + +/** Security and privacy skills. */ +const security = /*#__PURE__*/ l.token($nsid, 'security') + +export { security } + +/** Security and privacy skills. */ +const Security = /*#__PURE__*/ security.value + +/** Security and privacy skills. */ +type Security = typeof Security + +export { Security } + +/** The type of opportunity the user is open to. */ +type OpenToWorkStatus = + | 'id.sifa.defs#fullTimeRoles' + | 'id.sifa.defs#partTimeRoles' + | 'id.sifa.defs#contractRoles' + | 'id.sifa.defs#commissions' + | 'id.sifa.defs#boardPositions' + | 'id.sifa.defs#mentoringOthers' + | 'id.sifa.defs#beingMentored' + | 'id.sifa.defs#collaborations' + | 'id.sifa.defs#speakingEngagements' + | l.UnknownString + +export type { OpenToWorkStatus } + +/** The type of opportunity the user is open to. */ +const openToWorkStatus = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#fullTimeRoles', + 'id.sifa.defs#partTimeRoles', + 'id.sifa.defs#contractRoles', + 'id.sifa.defs#commissions', + 'id.sifa.defs#boardPositions', + 'id.sifa.defs#mentoringOthers', + 'id.sifa.defs#beingMentored', + 'id.sifa.defs#collaborations', + 'id.sifa.defs#speakingEngagements', + ] +}>() + +export { openToWorkStatus } + +/** Open to full-time employment opportunities. */ +const fullTimeRoles = /*#__PURE__*/ l.token($nsid, 'fullTimeRoles') + +export { fullTimeRoles } + +/** Open to full-time employment opportunities. */ +const FullTimeRoles = /*#__PURE__*/ fullTimeRoles.value + +/** Open to full-time employment opportunities. */ +type FullTimeRoles = typeof FullTimeRoles + +export { FullTimeRoles } + +/** Open to part-time employment opportunities. */ +const partTimeRoles = /*#__PURE__*/ l.token($nsid, 'partTimeRoles') + +export { partTimeRoles } + +/** Open to part-time employment opportunities. */ +const PartTimeRoles = /*#__PURE__*/ partTimeRoles.value + +/** Open to part-time employment opportunities. */ +type PartTimeRoles = typeof PartTimeRoles + +export { PartTimeRoles } + +/** Open to B2B contract or project-based freelance work, consulting, contract development. */ +const contractRoles = /*#__PURE__*/ l.token($nsid, 'contractRoles') + +export { contractRoles } + +/** Open to B2B contract or project-based freelance work, consulting, contract development. */ +const ContractRoles = /*#__PURE__*/ contractRoles.value + +/** Open to B2B contract or project-based freelance work, consulting, contract development. */ +type ContractRoles = typeof ContractRoles + +export { ContractRoles } + +/** Open to commissioned creative work (illustration, design, voice work, music, etc.). */ +const commissions = /*#__PURE__*/ l.token($nsid, 'commissions') + +export { commissions } + +/** Open to commissioned creative work (illustration, design, voice work, music, etc.). */ +const Commissions = /*#__PURE__*/ commissions.value + +/** Open to commissioned creative work (illustration, design, voice work, music, etc.). */ +type Commissions = typeof Commissions + +export { Commissions } + +/** Open to advisory or board positions. */ +const boardPositions = /*#__PURE__*/ l.token($nsid, 'boardPositions') + +export { boardPositions } + +/** Open to advisory or board positions. */ +const BoardPositions = /*#__PURE__*/ boardPositions.value + +/** Open to advisory or board positions. */ +type BoardPositions = typeof BoardPositions + +export { BoardPositions } + +/** Open to mentoring others. */ +const mentoringOthers = /*#__PURE__*/ l.token($nsid, 'mentoringOthers') + +export { mentoringOthers } + +/** Open to mentoring others. */ +const MentoringOthers = /*#__PURE__*/ mentoringOthers.value + +/** Open to mentoring others. */ +type MentoringOthers = typeof MentoringOthers + +export { MentoringOthers } + +/** Open to being mentored. */ +const beingMentored = /*#__PURE__*/ l.token($nsid, 'beingMentored') + +export { beingMentored } + +/** Open to being mentored. */ +const BeingMentored = /*#__PURE__*/ beingMentored.value + +/** Open to being mentored. */ +type BeingMentored = typeof BeingMentored + +export { BeingMentored } + +/** Open to project collaborations. */ +const collaborations = /*#__PURE__*/ l.token($nsid, 'collaborations') + +export { collaborations } + +/** Open to project collaborations. */ +const Collaborations = /*#__PURE__*/ collaborations.value + +/** Open to project collaborations. */ +type Collaborations = typeof Collaborations + +export { Collaborations } + +/** Open to speaking engagements (talks, panels, keynotes, workshops). */ +const speakingEngagements = /*#__PURE__*/ l.token($nsid, 'speakingEngagements') + +export { speakingEngagements } + +/** Open to speaking engagements (talks, panels, keynotes, workshops). */ +const SpeakingEngagements = /*#__PURE__*/ speakingEngagements.value + +/** Open to speaking engagements (talks, panels, keynotes, workshops). */ +type SpeakingEngagements = typeof SpeakingEngagements + +export { SpeakingEngagements } + +/** Platform type for an external account linked to a Sifa profile. */ +type ExternalPlatform = + | 'id.sifa.defs#platformRss' + | 'id.sifa.defs#platformFediverse' + | 'id.sifa.defs#platformTwitter' + | 'id.sifa.defs#platformInstagram' + | 'id.sifa.defs#platformGithub' + | 'id.sifa.defs#platformCodeberg' + | 'id.sifa.defs#platformGitlab' + | 'id.sifa.defs#platformForgejo' + | 'id.sifa.defs#platformGitea' + | 'id.sifa.defs#platformYoutube' + | 'id.sifa.defs#platformLinkedin' + | 'id.sifa.defs#platformSubstack' + | 'id.sifa.defs#platformWebsite' + | 'id.sifa.defs#platformOrcid' + | 'id.sifa.defs#platformOther' + | l.UnknownString + +export type { ExternalPlatform } + +/** Platform type for an external account linked to a Sifa profile. */ +const externalPlatform = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#platformRss', + 'id.sifa.defs#platformFediverse', + 'id.sifa.defs#platformTwitter', + 'id.sifa.defs#platformInstagram', + 'id.sifa.defs#platformGithub', + 'id.sifa.defs#platformCodeberg', + 'id.sifa.defs#platformGitlab', + 'id.sifa.defs#platformForgejo', + 'id.sifa.defs#platformGitea', + 'id.sifa.defs#platformYoutube', + 'id.sifa.defs#platformLinkedin', + 'id.sifa.defs#platformSubstack', + 'id.sifa.defs#platformWebsite', + 'id.sifa.defs#platformOrcid', + 'id.sifa.defs#platformOther', + ] +}>() + +export { externalPlatform } + +/** RSS or Atom feed (blog, newsletter, podcast). */ +const platformRss = /*#__PURE__*/ l.token($nsid, 'platformRss') + +export { platformRss } + +/** RSS or Atom feed (blog, newsletter, podcast). */ +const PlatformRss = /*#__PURE__*/ platformRss.value + +/** RSS or Atom feed (blog, newsletter, podcast). */ +type PlatformRss = typeof PlatformRss + +export { PlatformRss } + +/** Fediverse account (Mastodon, Misskey, Pleroma, etc.). */ +const platformFediverse = /*#__PURE__*/ l.token($nsid, 'platformFediverse') + +export { platformFediverse } + +/** Fediverse account (Mastodon, Misskey, Pleroma, etc.). */ +const PlatformFediverse = /*#__PURE__*/ platformFediverse.value + +/** Fediverse account (Mastodon, Misskey, Pleroma, etc.). */ +type PlatformFediverse = typeof PlatformFediverse + +export { PlatformFediverse } + +/** Twitter/X account. */ +const platformTwitter = /*#__PURE__*/ l.token($nsid, 'platformTwitter') + +export { platformTwitter } + +/** Twitter/X account. */ +const PlatformTwitter = /*#__PURE__*/ platformTwitter.value + +/** Twitter/X account. */ +type PlatformTwitter = typeof PlatformTwitter + +export { PlatformTwitter } + +/** Instagram account. */ +const platformInstagram = /*#__PURE__*/ l.token($nsid, 'platformInstagram') + +export { platformInstagram } + +/** Instagram account. */ +const PlatformInstagram = /*#__PURE__*/ platformInstagram.value + +/** Instagram account. */ +type PlatformInstagram = typeof PlatformInstagram + +export { PlatformInstagram } + +/** GitHub account. */ +const platformGithub = /*#__PURE__*/ l.token($nsid, 'platformGithub') + +export { platformGithub } + +/** GitHub account. */ +const PlatformGithub = /*#__PURE__*/ platformGithub.value + +/** GitHub account. */ +type PlatformGithub = typeof PlatformGithub + +export { PlatformGithub } + +/** Codeberg account. */ +const platformCodeberg = /*#__PURE__*/ l.token($nsid, 'platformCodeberg') + +export { platformCodeberg } + +/** Codeberg account. */ +const PlatformCodeberg = /*#__PURE__*/ platformCodeberg.value + +/** Codeberg account. */ +type PlatformCodeberg = typeof PlatformCodeberg + +export { PlatformCodeberg } + +/** GitLab account (gitlab.com or self-hosted). */ +const platformGitlab = /*#__PURE__*/ l.token($nsid, 'platformGitlab') + +export { platformGitlab } + +/** GitLab account (gitlab.com or self-hosted). */ +const PlatformGitlab = /*#__PURE__*/ platformGitlab.value + +/** GitLab account (gitlab.com or self-hosted). */ +type PlatformGitlab = typeof PlatformGitlab + +export { PlatformGitlab } + +/** Forgejo account on a self-hosted instance other than Codeberg. */ +const platformForgejo = /*#__PURE__*/ l.token($nsid, 'platformForgejo') + +export { platformForgejo } + +/** Forgejo account on a self-hosted instance other than Codeberg. */ +const PlatformForgejo = /*#__PURE__*/ platformForgejo.value + +/** Forgejo account on a self-hosted instance other than Codeberg. */ +type PlatformForgejo = typeof PlatformForgejo + +export { PlatformForgejo } + +/** Gitea account on a self-hosted instance. */ +const platformGitea = /*#__PURE__*/ l.token($nsid, 'platformGitea') + +export { platformGitea } + +/** Gitea account on a self-hosted instance. */ +const PlatformGitea = /*#__PURE__*/ platformGitea.value + +/** Gitea account on a self-hosted instance. */ +type PlatformGitea = typeof PlatformGitea + +export { PlatformGitea } + +/** YouTube channel. */ +const platformYoutube = /*#__PURE__*/ l.token($nsid, 'platformYoutube') + +export { platformYoutube } + +/** YouTube channel. */ +const PlatformYoutube = /*#__PURE__*/ platformYoutube.value + +/** YouTube channel. */ +type PlatformYoutube = typeof PlatformYoutube + +export { PlatformYoutube } + +/** LinkedIn profile. */ +const platformLinkedin = /*#__PURE__*/ l.token($nsid, 'platformLinkedin') + +export { platformLinkedin } + +/** LinkedIn profile. */ +const PlatformLinkedin = /*#__PURE__*/ platformLinkedin.value + +/** LinkedIn profile. */ +type PlatformLinkedin = typeof PlatformLinkedin + +export { PlatformLinkedin } + +/** Substack newsletter. */ +const platformSubstack = /*#__PURE__*/ l.token($nsid, 'platformSubstack') + +export { platformSubstack } + +/** Substack newsletter. */ +const PlatformSubstack = /*#__PURE__*/ platformSubstack.value + +/** Substack newsletter. */ +type PlatformSubstack = typeof PlatformSubstack + +export { PlatformSubstack } + +/** Personal or professional website. */ +const platformWebsite = /*#__PURE__*/ l.token($nsid, 'platformWebsite') + +export { platformWebsite } + +/** Personal or professional website. */ +const PlatformWebsite = /*#__PURE__*/ platformWebsite.value + +/** Personal or professional website. */ +type PlatformWebsite = typeof PlatformWebsite + +export { PlatformWebsite } + +/** ORCID researcher identifier. */ +const platformOrcid = /*#__PURE__*/ l.token($nsid, 'platformOrcid') + +export { platformOrcid } + +/** ORCID researcher identifier. */ +const PlatformOrcid = /*#__PURE__*/ platformOrcid.value + +/** ORCID researcher identifier. */ +type PlatformOrcid = typeof PlatformOrcid + +export { PlatformOrcid } + +/** Other platform not covered by specific tokens. */ +const platformOther = /*#__PURE__*/ l.token($nsid, 'platformOther') + +export { platformOther } + +/** Other platform not covered by specific tokens. */ +const PlatformOther = /*#__PURE__*/ platformOther.value + +/** Other platform not covered by specific tokens. */ +type PlatformOther = typeof PlatformOther + +export { PlatformOther } + +/** The role a location plays in a user's professional profile. */ +type LocationType = + | 'id.sifa.defs#locationPrimary' + | 'id.sifa.defs#locationBusiness' + | 'id.sifa.defs#locationTravel' + | l.UnknownString + +export type { LocationType } + +/** The role a location plays in a user's professional profile. */ +const locationType = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#locationPrimary', + 'id.sifa.defs#locationBusiness', + 'id.sifa.defs#locationTravel', + ] +}>() + +export { locationType } + +/** Primary residence or home location. */ +const locationPrimary = /*#__PURE__*/ l.token($nsid, 'locationPrimary') + +export { locationPrimary } + +/** Primary residence or home location. */ +const LocationPrimary = /*#__PURE__*/ locationPrimary.value + +/** Primary residence or home location. */ +type LocationPrimary = typeof LocationPrimary + +export { LocationPrimary } + +/** Business or operational location. */ +const locationBusiness = /*#__PURE__*/ l.token($nsid, 'locationBusiness') + +export { locationBusiness } + +/** Business or operational location. */ +const LocationBusiness = /*#__PURE__*/ locationBusiness.value + +/** Business or operational location. */ +type LocationBusiness = typeof LocationBusiness + +export { LocationBusiness } + +/** Frequent travel or temporary location. */ +const locationTravel = /*#__PURE__*/ l.token($nsid, 'locationTravel') + +export { locationTravel } + +/** Frequent travel or temporary location. */ +const LocationTravel = /*#__PURE__*/ locationTravel.value + +/** Frequent travel or temporary location. */ +type LocationTravel = typeof LocationTravel + +export { LocationTravel } + +/** A reference to an id.sifa.profile.skill record by AT-URI. No CID is required because skills are mutable records in the same user's repo. */ +type SkillRef = { + $type?: 'id.sifa.defs#skillRef' + + /** + * AT-URI of the id.sifa.profile.skill record. + */ + uri: l.AtUriString +} + +export type { SkillRef } + +/** A reference to an id.sifa.profile.skill record by AT-URI. No CID is required because skills are mutable records in the same user's repo. */ +const skillRef = /*#__PURE__*/ l.typedObject( + $nsid, + 'skillRef', + /*#__PURE__*/ l.object({ uri: /*#__PURE__*/ l.string({ format: 'at-uri' }) }), +) + +export { skillRef } + +/** A reference to an organization or person named by a record: a human label plus stable machine anchors. The name is a point-in-time snapshot captured when the record was saved; did and entityRef are the durable identity and should be resolved live. Consumers render the name, and follow did or entityRef to reach the current entity. */ +type AgentRef = { + $type?: 'id.sifa.defs#agentRef' + + /** + * Human-readable label for the organization or person, as it was known when the record was saved. A point-in-time snapshot, not refreshed from a lookup. + */ + name: string + + /** + * DID of the referenced organization or person's atproto account, if one exists. The stable identity: it survives handle and name changes. + */ + did?: l.DidString + + /** + * Portable, app-neutral identifier for the referenced organization: a Wikidata Q-ID URI, a ROR URI, or an LEI URI, else a resolver URL. Enables deterministic resolution to a canonical entity even before the organization claims an atproto account. Absent for a bare person or a free-text entry. + */ + entityRef?: l.UriString +} + +export type { AgentRef } + +/** A reference to an organization or person named by a record: a human label plus stable machine anchors. The name is a point-in-time snapshot captured when the record was saved; did and entityRef are the durable identity and should be resolved live. Consumers render the name, and follow did or entityRef to reach the current entity. */ +const agentRef = /*#__PURE__*/ l.typedObject( + $nsid, + 'agentRef', + /*#__PURE__*/ l.object({ + name: /*#__PURE__*/ l.string({ maxGraphemes: 256, maxLength: 2560 }), + did: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string({ format: 'did' })), + entityRef: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ format: 'uri' }), + ), + }), +) + +export { agentRef } + +/** Role within a collaborative project. */ +type ProjectRole = + | 'id.sifa.defs#projectOwner' + | 'id.sifa.defs#projectCore' + | 'id.sifa.defs#projectContributor' + | l.UnknownString + +export type { ProjectRole } + +/** Role within a collaborative project. */ +const projectRole = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#projectOwner', + 'id.sifa.defs#projectCore', + 'id.sifa.defs#projectContributor', + ] +}>() + +export { projectRole } + +/** Project owner with full management permissions. Multiple owners are supported. */ +const projectOwner = /*#__PURE__*/ l.token($nsid, 'projectOwner') + +export { projectOwner } + +/** Project owner with full management permissions. Multiple owners are supported. */ +const ProjectOwner = /*#__PURE__*/ projectOwner.value + +/** Project owner with full management permissions. Multiple owners are supported. */ +type ProjectOwner = typeof ProjectOwner + +export { ProjectOwner } + +/** Core team member with elevated involvement. */ +const projectCore = /*#__PURE__*/ l.token($nsid, 'projectCore') + +export { projectCore } + +/** Core team member with elevated involvement. */ +const ProjectCore = /*#__PURE__*/ projectCore.value + +/** Core team member with elevated involvement. */ +type ProjectCore = typeof ProjectCore + +export { ProjectCore } + +/** Project contributor. */ +const projectContributor = /*#__PURE__*/ l.token($nsid, 'projectContributor') + +export { projectContributor } + +/** Project contributor. */ +const ProjectContributor = /*#__PURE__*/ projectContributor.value + +/** Project contributor. */ +type ProjectContributor = typeof ProjectContributor + +export { ProjectContributor } + +/** Current status of a collaborative project. */ +type ProjectStatus = + | 'id.sifa.defs#projectActive' + | 'id.sifa.defs#projectCompleted' + | 'id.sifa.defs#projectArchived' + | l.UnknownString + +export type { ProjectStatus } + +/** Current status of a collaborative project. */ +const projectStatus = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#projectActive', + 'id.sifa.defs#projectCompleted', + 'id.sifa.defs#projectArchived', + ] +}>() + +export { projectStatus } + +/** Project is actively maintained or in development. */ +const projectActive = /*#__PURE__*/ l.token($nsid, 'projectActive') + +export { projectActive } + +/** Project is actively maintained or in development. */ +const ProjectActive = /*#__PURE__*/ projectActive.value + +/** Project is actively maintained or in development. */ +type ProjectActive = typeof ProjectActive + +export { ProjectActive } + +/** Project has been completed. */ +const projectCompleted = /*#__PURE__*/ l.token($nsid, 'projectCompleted') + +export { projectCompleted } + +/** Project has been completed. */ +const ProjectCompleted = /*#__PURE__*/ projectCompleted.value + +/** Project has been completed. */ +type ProjectCompleted = typeof ProjectCompleted + +export { ProjectCompleted } + +/** Project is archived and no longer active. */ +const projectArchived = /*#__PURE__*/ l.token($nsid, 'projectArchived') + +export { projectArchived } + +/** Project is archived and no longer active. */ +const ProjectArchived = /*#__PURE__*/ projectArchived.value + +/** Project is archived and no longer active. */ +type ProjectArchived = typeof ProjectArchived + +export { ProjectArchived } + +/** What an id.sifa.confirmation record affirms. Open set. */ +type ConfirmationRelation = + | 'id.sifa.defs#coSpeaker' + | 'id.sifa.defs#projectMember' + | 'id.sifa.defs#author' + | 'id.sifa.defs#collaborator' + | 'id.sifa.defs#colleague' + | l.UnknownString + +export type { ConfirmationRelation } + +/** What an id.sifa.confirmation record affirms. Open set. */ +const confirmationRelation = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#coSpeaker', + 'id.sifa.defs#projectMember', + 'id.sifa.defs#author', + 'id.sifa.defs#collaborator', + 'id.sifa.defs#colleague', + ] +}>() + +export { confirmationRelation } + +/** The named person presented alongside the claimer at the referenced id.sifa.profile.presentationDelivery occasion. */ +const coSpeaker = /*#__PURE__*/ l.token($nsid, 'coSpeaker') + +export { coSpeaker } + +/** The named person presented alongside the claimer at the referenced id.sifa.profile.presentationDelivery occasion. */ +const CoSpeaker = /*#__PURE__*/ coSpeaker.value + +/** The named person presented alongside the claimer at the referenced id.sifa.profile.presentationDelivery occasion. */ +type CoSpeaker = typeof CoSpeaker + +export { CoSpeaker } + +/** The named person worked on the referenced id.sifa.profile.project. */ +const projectMember = /*#__PURE__*/ l.token($nsid, 'projectMember') + +export { projectMember } + +/** The named person worked on the referenced id.sifa.profile.project. */ +const ProjectMember = /*#__PURE__*/ projectMember.value + +/** The named person worked on the referenced id.sifa.profile.project. */ +type ProjectMember = typeof ProjectMember + +export { ProjectMember } + +/** The named person co-authored the referenced id.sifa.profile.publication. */ +const author = /*#__PURE__*/ l.token($nsid, 'author') + +export { author } + +/** The named person co-authored the referenced id.sifa.profile.publication. */ +const Author = /*#__PURE__*/ author.value + +/** The named person co-authored the referenced id.sifa.profile.publication. */ +type Author = typeof Author + +export { Author } + +/** The named person worked alongside the claimer on the referenced id.sifa.profile.involvement. */ +const collaborator = /*#__PURE__*/ l.token($nsid, 'collaborator') + +export { collaborator } + +/** The named person worked alongside the claimer on the referenced id.sifa.profile.involvement. */ +const Collaborator = /*#__PURE__*/ collaborator.value + +/** The named person worked alongside the claimer on the referenced id.sifa.profile.involvement. */ +type Collaborator = typeof Collaborator + +export { Collaborator } + +/** The confirming person worked with the owner of the referenced id.sifa.profile.position at the same organization. Unlike the other relations, the subject record names its owner rather than the confirming person. An organization account can write this too, but it stays a colleague-level confirmation: the organization-verified tier comes only from an id.sifa.org.employmentAttestation in the organization's own repository. */ +const colleague = /*#__PURE__*/ l.token($nsid, 'colleague') + +export { colleague } + +/** The confirming person worked with the owner of the referenced id.sifa.profile.position at the same organization. Unlike the other relations, the subject record names its owner rather than the confirming person. An organization account can write this too, but it stays a colleague-level confirmation: the organization-verified tier comes only from an id.sifa.org.employmentAttestation in the organization's own repository. */ +const Colleague = /*#__PURE__*/ colleague.value + +/** The confirming person worked with the owner of the referenced id.sifa.profile.position at the same organization. Unlike the other relations, the subject record names its owner rather than the confirming person. An organization account can write this too, but it stays a colleague-level confirmation: the organization-verified tier comes only from an id.sifa.org.employmentAttestation in the organization's own repository. */ +type Colleague = typeof Colleague + +export { Colleague } + +/** Another person named as a member of a project. A claim by the record author, not a fact: it carries the named person's display name, avatar, and profile link only once they publish a matching id.sifa.confirmation. */ +type ProjectMemberRef = { + $type?: 'id.sifa.defs#projectMemberRef' + + /** + * DID of the person named as a project member. Any atproto account is allowed. + */ + did: l.DidString + + /** + * Role the named person held on the project. Display only: it grants no write access to the project record, which lives in the author's repository. + */ + role?: + | 'id.sifa.defs#projectOwner' + | 'id.sifa.defs#projectCore' + | 'id.sifa.defs#projectContributor' + | l.UnknownString + + /** + * Optional title within the project (e.g. 'Lead Designer', 'Backend Engineer'). + */ + title?: string +} + +export type { ProjectMemberRef } + +/** Another person named as a member of a project. A claim by the record author, not a fact: it carries the named person's display name, avatar, and profile link only once they publish a matching id.sifa.confirmation. */ +const projectMemberRef = /*#__PURE__*/ l.typedObject( + $nsid, + 'projectMemberRef', + /*#__PURE__*/ l.object({ + did: /*#__PURE__*/ l.string({ format: 'did' }), + role: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#projectOwner', + 'id.sifa.defs#projectCore', + 'id.sifa.defs#projectContributor', + ] + }>(), + ), + title: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 128, maxLength: 1280 }), + ), + }), +) + +export { projectMemberRef } + +/** A reference to a record in another repository or lexicon by AT-URI. The CID is optional: it pins a specific version as an integrity hint, but consumers should resolve the AT-URI live so the reference tracks edits to the target. */ +type ExternalRecordRef = { + $type?: 'id.sifa.defs#externalRecordRef' + + /** + * AT-URI of the referenced record. + */ + uri: l.AtUriString + + /** + * Optional CID of a specific version of the referenced record. Used as an integrity hint only; live resolution is by AT-URI. + */ + cid?: l.CidString +} + +export type { ExternalRecordRef } + +/** A reference to a record in another repository or lexicon by AT-URI. The CID is optional: it pins a specific version as an integrity hint, but consumers should resolve the AT-URI live so the reference tracks edits to the target. */ +const externalRecordRef = /*#__PURE__*/ l.typedObject( + $nsid, + 'externalRecordRef', + /*#__PURE__*/ l.object({ + uri: /*#__PURE__*/ l.string({ format: 'at-uri' }), + cid: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string({ format: 'cid' })), + }), +) + +export { externalRecordRef } + +/** The user's role in a presentation or session. Open set. */ +type PresentationRole = + | 'id.sifa.defs#presenter' + | 'id.sifa.defs#panelist' + | 'id.sifa.defs#keynote' + | 'id.sifa.defs#workshop' + | 'id.sifa.defs#host' + | l.UnknownString + +export type { PresentationRole } + +/** The user's role in a presentation or session. Open set. */ +const presentationRole = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#presenter', + 'id.sifa.defs#panelist', + 'id.sifa.defs#keynote', + 'id.sifa.defs#workshop', + 'id.sifa.defs#host', + ] +}>() + +export { presentationRole } + +/** A typed link from this work to another version or form of it, such as the published version of a preprint. Values mirror the DataCite relatedIdentifier vocabulary so they round-trip with DataCite and Crossref metadata. */ +type RelatedIdentifier = { + $type?: 'id.sifa.defs#relatedIdentifier' + + /** + * The related work: a bare DOI ("10.1234/example"), an AT-URI of another record, or a URL, as named by identifierType. + */ + identifier: string + + /** + * Kind of identifier. Absent means DOI. + */ + identifierType?: 'DOI' | 'AT-URI' | 'URL' | l.UnknownString + + /** + * How this work relates to the identified one, in DataCite relationType terms. For example IsPreprintOf on a preprint points at its published version. + */ + relationType: + | 'IsPreprintOf' + | 'HasPreprint' + | 'IsPublishedIn' + | 'IsVersionOf' + | 'HasVersion' + | 'IsNewVersionOf' + | 'IsPreviousVersionOf' + | 'IsIdenticalTo' + | l.UnknownString +} + +export type { RelatedIdentifier } + +/** A typed link from this work to another version or form of it, such as the published version of a preprint. Values mirror the DataCite relatedIdentifier vocabulary so they round-trip with DataCite and Crossref metadata. */ +const relatedIdentifier = /*#__PURE__*/ l.typedObject( + $nsid, + 'relatedIdentifier', + /*#__PURE__*/ l.object({ + identifier: /*#__PURE__*/ l.string({ maxLength: 2048 }), + identifierType: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + maxLength: 32 + knownValues: ['DOI', 'AT-URI', 'URL'] + }>({ maxLength: 32 }), + ), + relationType: /*#__PURE__*/ l.string<{ + maxLength: 64 + knownValues: [ + 'IsPreprintOf', + 'HasPreprint', + 'IsPublishedIn', + 'IsVersionOf', + 'HasVersion', + 'IsNewVersionOf', + 'IsPreviousVersionOf', + 'IsIdenticalTo', + ] + }>({ maxLength: 64 }), + }), +) + +export { relatedIdentifier } + +/** Delivered the session as the speaker or presenter (spoken or non-spoken). */ +const presenter = /*#__PURE__*/ l.token($nsid, 'presenter') + +export { presenter } + +/** Delivered the session as the speaker or presenter (spoken or non-spoken). */ +const Presenter = /*#__PURE__*/ presenter.value + +/** Delivered the session as the speaker or presenter (spoken or non-spoken). */ +type Presenter = typeof Presenter + +export { Presenter } + +/** Participated as a member of a panel. */ +const panelist = /*#__PURE__*/ l.token($nsid, 'panelist') + +export { panelist } + +/** Participated as a member of a panel. */ +const Panelist = /*#__PURE__*/ panelist.value + +/** Participated as a member of a panel. */ +type Panelist = typeof Panelist + +export { Panelist } + +/** Gave a keynote address. */ +const keynote = /*#__PURE__*/ l.token($nsid, 'keynote') + +export { keynote } + +/** Gave a keynote address. */ +const Keynote = /*#__PURE__*/ keynote.value + +/** Gave a keynote address. */ +type Keynote = typeof Keynote + +export { Keynote } + +/** Led or facilitated a workshop or tutorial. */ +const workshop = /*#__PURE__*/ l.token($nsid, 'workshop') + +export { workshop } + +/** Led or facilitated a workshop or tutorial. */ +const Workshop = /*#__PURE__*/ workshop.value + +/** Led or facilitated a workshop or tutorial. */ +type Workshop = typeof Workshop + +export { Workshop } + +/** Hosted or moderated the session, including acting as MC, moderator, or host of a podcast or livestream recorded there. Organizing the event itself is recorded as an id.sifa.profile.project whose events field references it, not as a delivery role. */ +const host = /*#__PURE__*/ l.token($nsid, 'host') + +export { host } + +/** Hosted or moderated the session, including acting as MC, moderator, or host of a podcast or livestream recorded there. Organizing the event itself is recorded as an id.sifa.profile.project whose events field references it, not as a delivery role. */ +const Host = /*#__PURE__*/ host.value + +/** Hosted or moderated the session, including acting as MC, moderator, or host of a podcast or livestream recorded there. Organizing the event itself is recorded as an id.sifa.profile.project whose events field references it, not as a delivery role. */ +type Host = typeof Host + +export { Host } + +/** The category of a related link on a presentation. Open set. */ +type PresentationLinkType = + | 'id.sifa.defs#linkSlides' + | 'id.sifa.defs#linkRecording' + | 'id.sifa.defs#linkEvent' + | 'id.sifa.defs#linkRegistration' + | 'id.sifa.defs#linkWriteup' + | 'id.sifa.defs#linkOther' + | l.UnknownString + +export type { PresentationLinkType } + +/** The category of a related link on a presentation. Open set. */ +const presentationLinkType = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#linkSlides', + 'id.sifa.defs#linkRecording', + 'id.sifa.defs#linkEvent', + 'id.sifa.defs#linkRegistration', + 'id.sifa.defs#linkWriteup', + 'id.sifa.defs#linkOther', + ] +}>() + +export { presentationLinkType } + +/** Slides or presentation deck. */ +const linkSlides = /*#__PURE__*/ l.token($nsid, 'linkSlides') + +export { linkSlides } + +/** Slides or presentation deck. */ +const LinkSlides = /*#__PURE__*/ linkSlides.value + +/** Slides or presentation deck. */ +type LinkSlides = typeof LinkSlides + +export { LinkSlides } + +/** Video or audio recording of the presentation. */ +const linkRecording = /*#__PURE__*/ l.token($nsid, 'linkRecording') + +export { linkRecording } + +/** Video or audio recording of the presentation. */ +const LinkRecording = /*#__PURE__*/ linkRecording.value + +/** Video or audio recording of the presentation. */ +type LinkRecording = typeof LinkRecording + +export { LinkRecording } + +/** The event or session page. */ +const linkEvent = /*#__PURE__*/ l.token($nsid, 'linkEvent') + +export { linkEvent } + +/** The event or session page. */ +const LinkEvent = /*#__PURE__*/ linkEvent.value + +/** The event or session page. */ +type LinkEvent = typeof LinkEvent + +export { LinkEvent } + +/** Registration or ticket page. */ +const linkRegistration = /*#__PURE__*/ l.token($nsid, 'linkRegistration') + +export { linkRegistration } + +/** Registration or ticket page. */ +const LinkRegistration = /*#__PURE__*/ linkRegistration.value + +/** Registration or ticket page. */ +type LinkRegistration = typeof LinkRegistration + +export { LinkRegistration } + +/** A long-form write-up, article, or transcript of the talk. */ +const linkWriteup = /*#__PURE__*/ l.token($nsid, 'linkWriteup') + +export { linkWriteup } + +/** A long-form write-up, article, or transcript of the talk. */ +const LinkWriteup = /*#__PURE__*/ linkWriteup.value + +/** A long-form write-up, article, or transcript of the talk. */ +type LinkWriteup = typeof LinkWriteup + +export { LinkWriteup } + +/** Other related link. */ +const linkOther = /*#__PURE__*/ l.token($nsid, 'linkOther') + +export { linkOther } + +/** Other related link. */ +const LinkOther = /*#__PURE__*/ linkOther.value + +/** Other related link. */ +type LinkOther = typeof LinkOther + +export { LinkOther } + +/** A related link for a presentation or one of its deliveries. */ +type PresentationLink = { + $type?: 'id.sifa.defs#presentationLink' + + /** + * The link URL. + */ + uri: l.UriString + + /** + * Optional display label (e.g., 'Watch recording', 'Slides'). + */ + label?: string + + /** + * Optional link category, used to pick an icon. Open set; see id.sifa.defs#presentationLinkType. + */ + type?: + | 'id.sifa.defs#linkSlides' + | 'id.sifa.defs#linkRecording' + | 'id.sifa.defs#linkEvent' + | 'id.sifa.defs#linkRegistration' + | 'id.sifa.defs#linkWriteup' + | 'id.sifa.defs#linkOther' + | l.UnknownString +} + +export type { PresentationLink } + +/** A related link for a presentation or one of its deliveries. */ +const presentationLink = /*#__PURE__*/ l.typedObject( + $nsid, + 'presentationLink', + /*#__PURE__*/ l.object({ + uri: /*#__PURE__*/ l.string({ format: 'uri' }), + label: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 64, maxLength: 640 }), + ), + type: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#linkSlides', + 'id.sifa.defs#linkRecording', + 'id.sifa.defs#linkEvent', + 'id.sifa.defs#linkRegistration', + 'id.sifa.defs#linkWriteup', + 'id.sifa.defs#linkOther', + ] + }>(), + ), + }), +) + +export { presentationLink } + +/** The nature of an involvement record. */ +type InvolvementKind = + | 'id.sifa.defs#involvementOpenSource' + | 'id.sifa.defs#involvementCommunity' + | 'id.sifa.defs#involvementCharity' + | 'id.sifa.defs#involvementCivic' + | 'id.sifa.defs#involvementOther' + | l.UnknownString + +export type { InvolvementKind } + +/** The nature of an involvement record. */ +const involvementKind = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#involvementOpenSource', + 'id.sifa.defs#involvementCommunity', + 'id.sifa.defs#involvementCharity', + 'id.sifa.defs#involvementCivic', + 'id.sifa.defs#involvementOther', + ] +}>() + +export { involvementKind } + +/** The user's role in a course: taking it, teaching it, or assisting with it. */ +type CourseRole = + | 'id.sifa.defs#courseTaken' + | 'id.sifa.defs#courseTaught' + | 'id.sifa.defs#courseTeachingAssistant' + | l.UnknownString + +export type { CourseRole } + +/** The user's role in a course: taking it, teaching it, or assisting with it. */ +const courseRole = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#courseTaken', + 'id.sifa.defs#courseTaught', + 'id.sifa.defs#courseTeachingAssistant', + ] +}>() + +export { courseRole } + +/** The user took the course as a student. */ +const courseTaken = /*#__PURE__*/ l.token($nsid, 'courseTaken') + +export { courseTaken } + +/** The user took the course as a student. */ +const CourseTaken = /*#__PURE__*/ courseTaken.value + +/** The user took the course as a student. */ +type CourseTaken = typeof CourseTaken + +export { CourseTaken } + +/** The user taught the course as an instructor or lecturer. */ +const courseTaught = /*#__PURE__*/ l.token($nsid, 'courseTaught') + +export { courseTaught } + +/** The user taught the course as an instructor or lecturer. */ +const CourseTaught = /*#__PURE__*/ courseTaught.value + +/** The user taught the course as an instructor or lecturer. */ +type CourseTaught = typeof CourseTaught + +export { CourseTaught } + +/** The user assisted with teaching the course, for example as a teaching assistant. */ +const courseTeachingAssistant = /*#__PURE__*/ l.token( + $nsid, + 'courseTeachingAssistant', +) + +export { courseTeachingAssistant } + +/** The user assisted with teaching the course, for example as a teaching assistant. */ +const CourseTeachingAssistant = /*#__PURE__*/ courseTeachingAssistant.value + +/** The user assisted with teaching the course, for example as a teaching assistant. */ +type CourseTeachingAssistant = typeof CourseTeachingAssistant + +export { CourseTeachingAssistant } + +/** Open-source contribution or maintainership. */ +const involvementOpenSource = /*#__PURE__*/ l.token( + $nsid, + 'involvementOpenSource', +) + +export { involvementOpenSource } + +/** Open-source contribution or maintainership. */ +const InvolvementOpenSource = /*#__PURE__*/ involvementOpenSource.value + +/** Open-source contribution or maintainership. */ +type InvolvementOpenSource = typeof InvolvementOpenSource + +export { InvolvementOpenSource } + +/** Community organizing, moderation, or meetup/event running. */ +const involvementCommunity = /*#__PURE__*/ l.token( + $nsid, + 'involvementCommunity', +) + +export { involvementCommunity } + +/** Community organizing, moderation, or meetup/event running. */ +const InvolvementCommunity = /*#__PURE__*/ involvementCommunity.value + +/** Community organizing, moderation, or meetup/event running. */ +type InvolvementCommunity = typeof InvolvementCommunity + +export { InvolvementCommunity } + +/** Charitable or volunteer work for a cause or person. */ +const involvementCharity = /*#__PURE__*/ l.token($nsid, 'involvementCharity') + +export { involvementCharity } + +/** Charitable or volunteer work for a cause or person. */ +const InvolvementCharity = /*#__PURE__*/ involvementCharity.value + +/** Charitable or volunteer work for a cause or person. */ +type InvolvementCharity = typeof InvolvementCharity + +export { InvolvementCharity } + +/** Board membership, policy, advisory, or public-consultation work. */ +const involvementCivic = /*#__PURE__*/ l.token($nsid, 'involvementCivic') + +export { involvementCivic } + +/** Board membership, policy, advisory, or public-consultation work. */ +const InvolvementCivic = /*#__PURE__*/ involvementCivic.value + +/** Board membership, policy, advisory, or public-consultation work. */ +type InvolvementCivic = typeof InvolvementCivic + +export { InvolvementCivic } + +/** Other uncompensated involvement. */ +const involvementOther = /*#__PURE__*/ l.token($nsid, 'involvementOther') + +export { involvementOther } + +/** Other uncompensated involvement. */ +const InvolvementOther = /*#__PURE__*/ involvementOther.value + +/** Other uncompensated involvement. */ +type InvolvementOther = typeof InvolvementOther + +export { InvolvementOther } + +/** How the capital went in. General partner is deliberately absent: running a fund is a role, recorded as an id.sifa.profile.position, and a partner's own commitment to their fund is a limitedPartner entry against that fund. */ +type InvestmentRole = + | 'id.sifa.defs#angelInvestment' + | 'id.sifa.defs#syndicateInvestment' + | 'id.sifa.defs#limitedPartner' + | 'id.sifa.defs#otherInvestment' + | l.UnknownString + +export type { InvestmentRole } + +/** How the capital went in. General partner is deliberately absent: running a fund is a role, recorded as an id.sifa.profile.position, and a partner's own commitment to their fund is a limitedPartner entry against that fund. */ +const investmentRole = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#angelInvestment', + 'id.sifa.defs#syndicateInvestment', + 'id.sifa.defs#limitedPartner', + 'id.sifa.defs#otherInvestment', + ] +}>() + +export { investmentRole } + +/** Direct investment in the person's own name, with the person choosing the deal. */ +const angelInvestment = /*#__PURE__*/ l.token($nsid, 'angelInvestment') + +export { angelInvestment } + +/** Direct investment in the person's own name, with the person choosing the deal. */ +const AngelInvestment = /*#__PURE__*/ angelInvestment.value + +/** Direct investment in the person's own name, with the person choosing the deal. */ +type AngelInvestment = typeof AngelInvestment + +export { AngelInvestment } + +/** Investment in a deal led by someone else, made through a per-deal pooled vehicle. */ +const syndicateInvestment = /*#__PURE__*/ l.token($nsid, 'syndicateInvestment') + +export { syndicateInvestment } + +/** Investment in a deal led by someone else, made through a per-deal pooled vehicle. */ +const SyndicateInvestment = /*#__PURE__*/ syndicateInvestment.value + +/** Investment in a deal led by someone else, made through a per-deal pooled vehicle. */ +type SyndicateInvestment = typeof SyndicateInvestment + +export { SyndicateInvestment } + +/** Capital committed to a fund rather than to a company. The person does not choose the fund's deals, and the named entity is the fund itself. */ +const limitedPartner = /*#__PURE__*/ l.token($nsid, 'limitedPartner') + +export { limitedPartner } + +/** Capital committed to a fund rather than to a company. The person does not choose the fund's deals, and the named entity is the fund itself. */ +const LimitedPartner = /*#__PURE__*/ limitedPartner.value + +/** Capital committed to a fund rather than to a company. The person does not choose the fund's deals, and the named entity is the fund itself. */ +type LimitedPartner = typeof LimitedPartner + +export { LimitedPartner } + +/** A capital position that fits none of the above. */ +const otherInvestment = /*#__PURE__*/ l.token($nsid, 'otherInvestment') + +export { otherInvestment } + +/** A capital position that fits none of the above. */ +const OtherInvestment = /*#__PURE__*/ otherInvestment.value + +/** A capital position that fits none of the above. */ +type OtherInvestment = typeof OtherInvestment + +export { OtherInvestment } + +/** The company's funding stage at the time the investment was made, not its stage today. */ +type InvestmentStage = + | 'id.sifa.defs#stagePreSeed' + | 'id.sifa.defs#stageSeed' + | 'id.sifa.defs#stageSeriesA' + | 'id.sifa.defs#stageSeriesB' + | 'id.sifa.defs#stageSeriesCPlus' + | 'id.sifa.defs#stageGrowth' + | 'id.sifa.defs#stageSecondary' + | 'id.sifa.defs#stageOther' + | l.UnknownString + +export type { InvestmentStage } + +/** The company's funding stage at the time the investment was made, not its stage today. */ +const investmentStage = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#stagePreSeed', + 'id.sifa.defs#stageSeed', + 'id.sifa.defs#stageSeriesA', + 'id.sifa.defs#stageSeriesB', + 'id.sifa.defs#stageSeriesCPlus', + 'id.sifa.defs#stageGrowth', + 'id.sifa.defs#stageSecondary', + 'id.sifa.defs#stageOther', + ] +}>() + +export { investmentStage } + +/** Pre-seed round. */ +const stagePreSeed = /*#__PURE__*/ l.token($nsid, 'stagePreSeed') + +export { stagePreSeed } + +/** Pre-seed round. */ +const StagePreSeed = /*#__PURE__*/ stagePreSeed.value + +/** Pre-seed round. */ +type StagePreSeed = typeof StagePreSeed + +export { StagePreSeed } + +/** Seed round. */ +const stageSeed = /*#__PURE__*/ l.token($nsid, 'stageSeed') + +export { stageSeed } + +/** Seed round. */ +const StageSeed = /*#__PURE__*/ stageSeed.value + +/** Seed round. */ +type StageSeed = typeof StageSeed + +export { StageSeed } + +/** Series A round. */ +const stageSeriesA = /*#__PURE__*/ l.token($nsid, 'stageSeriesA') + +export { stageSeriesA } + +/** Series A round. */ +const StageSeriesA = /*#__PURE__*/ stageSeriesA.value + +/** Series A round. */ +type StageSeriesA = typeof StageSeriesA + +export { StageSeriesA } + +/** Series B round. */ +const stageSeriesB = /*#__PURE__*/ l.token($nsid, 'stageSeriesB') + +export { stageSeriesB } + +/** Series B round. */ +const StageSeriesB = /*#__PURE__*/ stageSeriesB.value + +/** Series B round. */ +type StageSeriesB = typeof StageSeriesB + +export { StageSeriesB } + +/** Series C or later round. */ +const stageSeriesCPlus = /*#__PURE__*/ l.token($nsid, 'stageSeriesCPlus') + +export { stageSeriesCPlus } + +/** Series C or later round. */ +const StageSeriesCPlus = /*#__PURE__*/ stageSeriesCPlus.value + +/** Series C or later round. */ +type StageSeriesCPlus = typeof StageSeriesCPlus + +export { StageSeriesCPlus } + +/** Growth or late-stage round. */ +const stageGrowth = /*#__PURE__*/ l.token($nsid, 'stageGrowth') + +export { stageGrowth } + +/** Growth or late-stage round. */ +const StageGrowth = /*#__PURE__*/ stageGrowth.value + +/** Growth or late-stage round. */ +type StageGrowth = typeof StageGrowth + +export { StageGrowth } + +/** Purchase of existing shares from another holder rather than newly issued shares. */ +const stageSecondary = /*#__PURE__*/ l.token($nsid, 'stageSecondary') + +export { stageSecondary } + +/** Purchase of existing shares from another holder rather than newly issued shares. */ +const StageSecondary = /*#__PURE__*/ stageSecondary.value + +/** Purchase of existing shares from another holder rather than newly issued shares. */ +type StageSecondary = typeof StageSecondary + +export { StageSecondary } + +/** A stage that fits none of the above, including rounds that predate the standard naming. */ +const stageOther = /*#__PURE__*/ l.token($nsid, 'stageOther') + +export { stageOther } + +/** A stage that fits none of the above, including rounds that predate the standard naming. */ +const StageOther = /*#__PURE__*/ stageOther.value + +/** A stage that fits none of the above, including rounds that predate the standard naming. */ +type StageOther = typeof StageOther + +export { StageOther } + +/** Where the position stands now. Recording a write-off is showing your work; Sifa never derives a hit rate or return from these values. */ +type InvestmentStatus = + | 'id.sifa.defs#investmentActive' + | 'id.sifa.defs#investmentExited' + | 'id.sifa.defs#investmentWrittenOff' + | 'id.sifa.defs#investmentUndisclosed' + | l.UnknownString + +export type { InvestmentStatus } + +/** Where the position stands now. Recording a write-off is showing your work; Sifa never derives a hit rate or return from these values. */ +const investmentStatus = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#investmentActive', + 'id.sifa.defs#investmentExited', + 'id.sifa.defs#investmentWrittenOff', + 'id.sifa.defs#investmentUndisclosed', + ] +}>() + +export { investmentStatus } + +/** The position is still held. */ +const investmentActive = /*#__PURE__*/ l.token($nsid, 'investmentActive') + +export { investmentActive } + +/** The position is still held. */ +const InvestmentActive = /*#__PURE__*/ investmentActive.value + +/** The position is still held. */ +type InvestmentActive = typeof InvestmentActive + +export { InvestmentActive } + +/** The position was realised through an acquisition, IPO, or secondary sale. */ +const investmentExited = /*#__PURE__*/ l.token($nsid, 'investmentExited') + +export { investmentExited } + +/** The position was realised through an acquisition, IPO, or secondary sale. */ +const InvestmentExited = /*#__PURE__*/ investmentExited.value + +/** The position was realised through an acquisition, IPO, or secondary sale. */ +type InvestmentExited = typeof InvestmentExited + +export { InvestmentExited } + +/** The company failed or the position was written down to nothing. */ +const investmentWrittenOff = /*#__PURE__*/ l.token( + $nsid, + 'investmentWrittenOff', +) + +export { investmentWrittenOff } + +/** The company failed or the position was written down to nothing. */ +const InvestmentWrittenOff = /*#__PURE__*/ investmentWrittenOff.value + +/** The company failed or the position was written down to nothing. */ +type InvestmentWrittenOff = typeof InvestmentWrittenOff + +export { InvestmentWrittenOff } + +/** The person prefers not to say where the position stands. */ +const investmentUndisclosed = /*#__PURE__*/ l.token( + $nsid, + 'investmentUndisclosed', +) + +export { investmentUndisclosed } + +/** The person prefers not to say where the position stands. */ +const InvestmentUndisclosed = /*#__PURE__*/ investmentUndisclosed.value + +/** The person prefers not to say where the position stands. */ +type InvestmentUndisclosed = typeof InvestmentUndisclosed + +export { InvestmentUndisclosed } + +/** An optional, deliberately structured amount. Free text was rejected here because an unparseable money string is worse than no amount at all. */ +type InvestmentAmount = { + $type?: 'id.sifa.defs#investmentAmount' + + /** + * Amount in whole major currency units (euros, not cents). Cheque sizes are round numbers, and whole units avoid the ambiguity of a bare figure. + */ + value: number + + /** + * ISO 4217 three-letter currency code, uppercase. Enforced at the app layer. + */ + currency: string +} + +export type { InvestmentAmount } + +/** An optional, deliberately structured amount. Free text was rejected here because an unparseable money string is worse than no amount at all. */ +const investmentAmount = /*#__PURE__*/ l.typedObject( + $nsid, + 'investmentAmount', + /*#__PURE__*/ l.object({ + value: /*#__PURE__*/ l.integer({ minimum: 0 }), + currency: /*#__PURE__*/ l.string({ minLength: 3, maxLength: 3 }), + }), +) + +export { investmentAmount } + +/** A public artifact proving a piece of work. Reusable across involvement, and later projects/publications. */ +type ArtifactLink = { + $type?: 'id.sifa.defs#artifactLink' + + /** + * URL of the artifact. + */ + url: l.UriString + + /** + * What this link points to. + */ + kind?: + | 'pull-request' + | 'issue' + | 'commit' + | 'review' + | 'release' + | 'talk' + | 'video' + | 'slides' + | 'article' + | 'thread' + | 'dataset' + | 'edit' + | 'other' + | l.UnknownString + + /** + * Optional human-readable label (e.g. 'Merged PR #1234: keep-alive support'). + */ + label?: string +} + +export type { ArtifactLink } + +/** A public artifact proving a piece of work. Reusable across involvement, and later projects/publications. */ +const artifactLink = /*#__PURE__*/ l.typedObject( + $nsid, + 'artifactLink', + /*#__PURE__*/ l.object({ + url: /*#__PURE__*/ l.string({ format: 'uri' }), + kind: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + knownValues: [ + 'pull-request', + 'issue', + 'commit', + 'review', + 'release', + 'talk', + 'video', + 'slides', + 'article', + 'thread', + 'dataset', + 'edit', + 'other', + ] + }>(), + ), + label: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 200, maxLength: 2000 }), + ), + }), +) + +export { artifactLink } + +/** Whether an employment relationship is ongoing or has ended. */ +type EmploymentStatus = + | 'id.sifa.defs#employmentCurrent' + | 'id.sifa.defs#employmentPast' + | l.UnknownString + +export type { EmploymentStatus } + +/** Whether an employment relationship is ongoing or has ended. */ +const employmentStatus = /*#__PURE__*/ l.string<{ + knownValues: ['id.sifa.defs#employmentCurrent', 'id.sifa.defs#employmentPast'] +}>() + +export { employmentStatus } + +/** The person currently holds the position. */ +const employmentCurrent = /*#__PURE__*/ l.token($nsid, 'employmentCurrent') + +export { employmentCurrent } + +/** The person currently holds the position. */ +const EmploymentCurrent = /*#__PURE__*/ employmentCurrent.value + +/** The person currently holds the position. */ +type EmploymentCurrent = typeof EmploymentCurrent + +export { EmploymentCurrent } + +/** The person held the position in the past. An end date gives the period. */ +const employmentPast = /*#__PURE__*/ l.token($nsid, 'employmentPast') + +export { employmentPast } + +/** The person held the position in the past. An end date gives the period. */ +const EmploymentPast = /*#__PURE__*/ employmentPast.value + +/** The person held the position in the past. An end date gives the period. */ +type EmploymentPast = typeof EmploymentPast + +export { EmploymentPast } + +/** How Sifa verified an employment: which evidence backs an id.sifa.verification.employment record. */ +type VerificationMethod = + | 'id.sifa.defs#verifiedByEmail' + | 'id.sifa.defs#verifiedByOrg' + | 'id.sifa.defs#verifiedByDirectory' + | 'id.sifa.defs#verifiedByPeer' + | l.UnknownString + +export type { VerificationMethod } + +/** How Sifa verified an employment: which evidence backs an id.sifa.verification.employment record. */ +const verificationMethod = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#verifiedByEmail', + 'id.sifa.defs#verifiedByOrg', + 'id.sifa.defs#verifiedByDirectory', + 'id.sifa.defs#verifiedByPeer', + ] +}>() + +export { verificationMethod } + +/** The person proved control of a mailbox at a domain recognized for the employing organization. Time-limited: the issued record carries expiresAt while this is the only method. */ +const verifiedByEmail = /*#__PURE__*/ l.token($nsid, 'verifiedByEmail') + +export { verifiedByEmail } + +/** The person proved control of a mailbox at a domain recognized for the employing organization. Time-limited: the issued record carries expiresAt while this is the only method. */ +const VerifiedByEmail = /*#__PURE__*/ verifiedByEmail.value + +/** The person proved control of a mailbox at a domain recognized for the employing organization. Time-limited: the issued record carries expiresAt while this is the only method. */ +type VerifiedByEmail = typeof VerifiedByEmail + +export { VerifiedByEmail } + +/** The organization's own account wrote an id.sifa.org.employmentAttestation for the position. */ +const verifiedByOrg = /*#__PURE__*/ l.token($nsid, 'verifiedByOrg') + +export { verifiedByOrg } + +/** The organization's own account wrote an id.sifa.org.employmentAttestation for the position. */ +const VerifiedByOrg = /*#__PURE__*/ verifiedByOrg.value + +/** The organization's own account wrote an id.sifa.org.employmentAttestation for the position. */ +type VerifiedByOrg = typeof VerifiedByOrg + +export { VerifiedByOrg } + +/** The organization's directory sync wrote the attestation on the organization's behalf. */ +const verifiedByDirectory = /*#__PURE__*/ l.token($nsid, 'verifiedByDirectory') + +export { verifiedByDirectory } + +/** The organization's directory sync wrote the attestation on the organization's behalf. */ +const VerifiedByDirectory = /*#__PURE__*/ verifiedByDirectory.value + +/** The organization's directory sync wrote the attestation on the organization's behalf. */ +type VerifiedByDirectory = typeof VerifiedByDirectory + +export { VerifiedByDirectory } + +/** Enough verified colleagues confirmed the position. Reserved: not published in the first version. */ +const verifiedByPeer = /*#__PURE__*/ l.token($nsid, 'verifiedByPeer') + +export { verifiedByPeer } + +/** Enough verified colleagues confirmed the position. Reserved: not published in the first version. */ +const VerifiedByPeer = /*#__PURE__*/ verifiedByPeer.value + +/** Enough verified colleagues confirmed the position. Reserved: not published in the first version. */ +type VerifiedByPeer = typeof VerifiedByPeer + +export { VerifiedByPeer } + +/** How an id.sifa.org.employmentAttestation came to be written. Absent means manual. */ +type AttestationSource = + | 'id.sifa.defs#attestationManual' + | 'id.sifa.defs#attestationDirectory' + | l.UnknownString + +export type { AttestationSource } + +/** How an id.sifa.org.employmentAttestation came to be written. Absent means manual. */ +const attestationSource = /*#__PURE__*/ l.string<{ + knownValues: [ + 'id.sifa.defs#attestationManual', + 'id.sifa.defs#attestationDirectory', + ] +}>() + +export { attestationSource } + +/** An account holder of the organization confirmed the employment by hand. */ +const attestationManual = /*#__PURE__*/ l.token($nsid, 'attestationManual') + +export { attestationManual } + +/** An account holder of the organization confirmed the employment by hand. */ +const AttestationManual = /*#__PURE__*/ attestationManual.value + +/** An account holder of the organization confirmed the employment by hand. */ +type AttestationManual = typeof AttestationManual + +export { AttestationManual } + +/** The organization's directory sync (for example SCIM) wrote the attestation. */ +const attestationDirectory = /*#__PURE__*/ l.token( + $nsid, + 'attestationDirectory', +) + +export { attestationDirectory } + +/** The organization's directory sync (for example SCIM) wrote the attestation. */ +const AttestationDirectory = /*#__PURE__*/ attestationDirectory.value + +/** The organization's directory sync (for example SCIM) wrote the attestation. */ +type AttestationDirectory = typeof AttestationDirectory + +export { AttestationDirectory } diff --git a/shared/lex/id/sifa/defs.ts b/shared/lex/id/sifa/defs.ts new file mode 100644 index 00000000..f3af51b8 --- /dev/null +++ b/shared/lex/id/sifa/defs.ts @@ -0,0 +1,5 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +export * from './defs.defs.ts' diff --git a/shared/lex/id/sifa/profile.ts b/shared/lex/id/sifa/profile.ts new file mode 100644 index 00000000..af0bc4e8 --- /dev/null +++ b/shared/lex/id/sifa/profile.ts @@ -0,0 +1,7 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +export * as presentation from './profile/presentation.ts' +export * as presentationDelivery from './profile/presentationDelivery.ts' +export * as project from './profile/project.ts' diff --git a/shared/lex/id/sifa/profile/presentation.defs.ts b/shared/lex/id/sifa/profile/presentation.defs.ts new file mode 100644 index 00000000..af54c032 --- /dev/null +++ b/shared/lex/id/sifa/profile/presentation.defs.ts @@ -0,0 +1,161 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +import { l } from '@atproto/lex-schema' +import * as SifaDefs from '../defs.defs.ts' + +const $nsid = 'id.sifa.profile.presentation' + +type $nsid = typeof $nsid + +export { $nsid } + +/** Record representing a single reusable presentation (the content), distinct from the occasions on which it is delivered. */ +type Main = { + $type: 'id.sifa.profile.presentation' + + /** + * Title of the presentation. + */ + title: string + + /** + * Description or abstract of the presentation. + */ + description?: string + + /** + * Typical length of the presentation, a fixed value or a range, in minutes. + */ + duration?: Duration + + /** + * Intended audiences for this presentation, open text (e.g. 'Engineering leaders', 'Beginners'). + */ + intendedAudiences?: string[] + + /** + * Canonical links for this content, such as slides or a recording. + */ + links?: SifaDefs.PresentationLink[] + + /** + * Optional reference to a long-form write-up of this presentation (a pub.leaflet.document or site.standard.document holding video, transcript, or article). + */ + writeupRef?: SifaDefs.ExternalRecordRef + + /** + * Optional cover image for the presentation. Rendered as the talk-page hero and OpenGraph image. Max 2 MB, PNG, JPEG, or WebP. + */ + coverImage?: l.BlobRef + + /** + * Whether this is the user's primary talk, surfaced in profile Highlights. Only reusable talks (not one-off sessions) may be primary. + */ + isPrimary?: boolean + + /** + * Client-declared timestamp when this record was originally created. + */ + createdAt: l.DatetimeString +} + +export type { Main } + +/** Record representing a single reusable presentation (the content), distinct from the occasions on which it is delivered. */ +const main = /*#__PURE__*/ l.record<'tid', Main>( + 'tid', + $nsid, + /*#__PURE__*/ l.object({ + title: /*#__PURE__*/ l.string({ + minLength: 1, + maxGraphemes: 300, + maxLength: 3000, + }), + description: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 5000, maxLength: 50000 }), + ), + duration: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref((() => duration) as any), + ), + intendedAudiences: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.array( + /*#__PURE__*/ l.string({ maxGraphemes: 100, maxLength: 1000 }), + { maxLength: 20 }, + ), + ), + links: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.array( + /*#__PURE__*/ l.ref( + (() => SifaDefs.presentationLink) as any, + ), + { maxLength: 20 }, + ), + ), + writeupRef: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => SifaDefs.externalRecordRef) as any, + ), + ), + coverImage: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.blob({ + accept: ['image/png', 'image/jpeg', 'image/webp'], + maxSize: 2000000, + }), + ), + isPrimary: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.boolean()), + createdAt: /*#__PURE__*/ l.string({ format: 'datetime' }), + }), +) + +export { main } + +const $type = $nsid + +type $type = typeof $type + +export { $type } + +export const $isTypeOf = /*#__PURE__*/ main.isTypeOf.bind(main) +export const $build = /*#__PURE__*/ main.build.bind(main) +export const $assert = /*#__PURE__*/ main.assert.bind(main) +export const $check = /*#__PURE__*/ main.check.bind(main) +export const $cast = /*#__PURE__*/ main.cast.bind(main) +export const $ifMatches = /*#__PURE__*/ main.ifMatches.bind(main) +export const $matches = /*#__PURE__*/ main.matches.bind(main) +export const $parse = /*#__PURE__*/ main.parse.bind(main) +export const $safeParse = /*#__PURE__*/ main.safeParse.bind(main) +export const $validate = /*#__PURE__*/ main.validate.bind(main) +export const $safeValidate = /*#__PURE__*/ main.safeValidate.bind(main) + +/** A presentation length in minutes: a fixed value (minMinutes only) or a range (minMinutes to maxMinutes). */ +type Duration = { + $type?: 'id.sifa.profile.presentation#duration' + + /** + * Length in minutes, or the lower bound when the length is offered as a range. + */ + minMinutes: number + + /** + * Upper bound in minutes when the length is offered as a range. Omit for a fixed length. + */ + maxMinutes?: number +} + +export type { Duration } + +/** A presentation length in minutes: a fixed value (minMinutes only) or a range (minMinutes to maxMinutes). */ +const duration = /*#__PURE__*/ l.typedObject( + $nsid, + 'duration', + /*#__PURE__*/ l.object({ + minMinutes: /*#__PURE__*/ l.integer({ minimum: 1 }), + maxMinutes: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.integer({ minimum: 1 }), + ), + }), +) + +export { duration } diff --git a/shared/lex/id/sifa/profile/presentation.ts b/shared/lex/id/sifa/profile/presentation.ts new file mode 100644 index 00000000..ce556d3b --- /dev/null +++ b/shared/lex/id/sifa/profile/presentation.ts @@ -0,0 +1,6 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +export * from './presentation.defs.ts' +export { main as default } from './presentation.defs.ts' diff --git a/shared/lex/id/sifa/profile/presentationDelivery.defs.ts b/shared/lex/id/sifa/profile/presentationDelivery.defs.ts new file mode 100644 index 00000000..d5141697 --- /dev/null +++ b/shared/lex/id/sifa/profile/presentationDelivery.defs.ts @@ -0,0 +1,211 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +import { l } from '@atproto/lex-schema' +import * as SifaDefs from '../defs.defs.ts' +import * as LocationAddress from '../../../community/lexicon/location/address.defs.ts' + +const $nsid = 'id.sifa.profile.presentationDelivery' + +type $nsid = typeof $nsid + +export { $nsid } + +/** Record representing a single occasion on which a presentation was delivered. This is the entry shown on a profile's activity timeline. At least one of presentationRef, title, or eventName is expected, enforced at the app layer. */ +type Main = { + $type: 'id.sifa.profile.presentationDelivery' + + /** + * Optional reference to the id.sifa.profile.presentation (the content) delivered here. When set, title, duration, and audiences are taken from it. + */ + presentationRef?: SifaDefs.ExternalRecordRef + + /** + * The same session as recorded on another person's profile. Set when you keep your own entry for work someone else has also recorded, so consumers can tell the two describe one thing rather than showing it twice. Each side stays its own record: the other person cannot edit yours, and yours does not change theirs. Resolve by AT-URI, since they will keep editing their copy. + */ + sameAs?: SifaDefs.ExternalRecordRef + + /** + * Fallback title for this delivery, used when no presentationRef is set. + */ + title?: string + + /** + * The presenter's role in this delivery. Open set; see id.sifa.defs#presentationRole. + */ + role?: + | 'id.sifa.defs#presenter' + | 'id.sifa.defs#panelist' + | 'id.sifa.defs#keynote' + | 'id.sifa.defs#workshop' + | 'id.sifa.defs#host' + | l.UnknownString + + /** + * Name of the event or venue. On the linked branch, hydrated from the calendar event's name. + */ + eventName?: string + + /** + * Calendar date of this delivery as YYYY-MM-DD, or YYYY-MM or YYYY when the exact day or month is not known (no time). Future dates are allowed for upcoming deliveries. The shape is enforced at the app layer. On the linked branch, derived from the event's startsAt in the event's own offset, and always a full day. + */ + date?: string + + /** + * Legacy free-text display location (city, country, or venue), retained for dual-read. Prefer the structured address field. On the linked branch, composed from the calendar event's structured locations. + */ + location?: string + + /** + * Structured delivery location. Sifa enforces ISO 3166-1 alpha-2 country codes at the app layer and surfaces country (for a flag) and locality (city); region, postalCode, and street are unused for deliveries. Takes precedence over the legacy location string when present. + */ + address?: LocationAddress.Main + + /** + * Whether this delivery was in person, virtual, or hybrid. Stores the full community.lexicon.calendar.event mode token; absent means in person. + */ + mode?: + | 'community.lexicon.calendar.event#inperson' + | 'community.lexicon.calendar.event#virtual' + | 'community.lexicon.calendar.event#hybrid' + | l.UnknownString + + /** + * Scheduling status of this delivery, typically hydrated from a linked calendar event. Stores the full community.lexicon.calendar.event status token. Consumers should surface cancelled and postponed states. + */ + status?: + | 'community.lexicon.calendar.event#scheduled' + | 'community.lexicon.calendar.event#cancelled' + | 'community.lexicon.calendar.event#postponed' + | 'community.lexicon.calendar.event#rescheduled' + | 'community.lexicon.calendar.event#planned' + | l.UnknownString + + /** + * Links specific to this delivery, such as the recording of this occasion. + */ + links?: SifaDefs.PresentationLink[] + + /** + * Optional reference to a community.lexicon.calendar.event for this occasion. Display fields are hydrated live from the target by AT-URI, with the stored fields as a fallback when the target is unavailable. + */ + eventRef?: SifaDefs.ExternalRecordRef + + /** + * DIDs of co-speakers who presented alongside the author at this occasion. Any atproto account is allowed; hydrated to profile cards on read and linked to the co-speaker's Sifa profile. + */ + coSpeakers?: l.DidString[] + + /** + * Client-declared timestamp when this record was originally created. + */ + createdAt: l.DatetimeString +} + +export type { Main } + +/** Record representing a single occasion on which a presentation was delivered. This is the entry shown on a profile's activity timeline. At least one of presentationRef, title, or eventName is expected, enforced at the app layer. */ +const main = /*#__PURE__*/ l.record<'tid', Main>( + 'tid', + $nsid, + /*#__PURE__*/ l.object({ + presentationRef: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => SifaDefs.externalRecordRef) as any, + ), + ), + sameAs: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => SifaDefs.externalRecordRef) as any, + ), + ), + title: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 300, maxLength: 3000 }), + ), + role: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + maxGraphemes: 64 + maxLength: 640 + knownValues: [ + 'id.sifa.defs#presenter', + 'id.sifa.defs#panelist', + 'id.sifa.defs#keynote', + 'id.sifa.defs#workshop', + 'id.sifa.defs#host', + ] + }>({ maxGraphemes: 64, maxLength: 640 }), + ), + eventName: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 300, maxLength: 3000 }), + ), + date: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string({ maxLength: 10 })), + location: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 256, maxLength: 2560 }), + ), + address: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => LocationAddress.main) as any, + ), + ), + mode: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + knownValues: [ + 'community.lexicon.calendar.event#inperson', + 'community.lexicon.calendar.event#virtual', + 'community.lexicon.calendar.event#hybrid', + ] + }>(), + ), + status: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string<{ + knownValues: [ + 'community.lexicon.calendar.event#scheduled', + 'community.lexicon.calendar.event#cancelled', + 'community.lexicon.calendar.event#postponed', + 'community.lexicon.calendar.event#rescheduled', + 'community.lexicon.calendar.event#planned', + ] + }>(), + ), + links: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.array( + /*#__PURE__*/ l.ref( + (() => SifaDefs.presentationLink) as any, + ), + { maxLength: 20 }, + ), + ), + eventRef: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => SifaDefs.externalRecordRef) as any, + ), + ), + coSpeakers: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.array(/*#__PURE__*/ l.string({ format: 'did' }), { + maxLength: 20, + }), + ), + createdAt: /*#__PURE__*/ l.string({ format: 'datetime' }), + }), +) + +export { main } + +const $type = $nsid + +type $type = typeof $type + +export { $type } + +export const $isTypeOf = /*#__PURE__*/ main.isTypeOf.bind(main) +export const $build = /*#__PURE__*/ main.build.bind(main) +export const $assert = /*#__PURE__*/ main.assert.bind(main) +export const $check = /*#__PURE__*/ main.check.bind(main) +export const $cast = /*#__PURE__*/ main.cast.bind(main) +export const $ifMatches = /*#__PURE__*/ main.ifMatches.bind(main) +export const $matches = /*#__PURE__*/ main.matches.bind(main) +export const $parse = /*#__PURE__*/ main.parse.bind(main) +export const $safeParse = /*#__PURE__*/ main.safeParse.bind(main) +export const $validate = /*#__PURE__*/ main.validate.bind(main) +export const $safeValidate = /*#__PURE__*/ main.safeValidate.bind(main) diff --git a/shared/lex/id/sifa/profile/presentationDelivery.ts b/shared/lex/id/sifa/profile/presentationDelivery.ts new file mode 100644 index 00000000..77d27648 --- /dev/null +++ b/shared/lex/id/sifa/profile/presentationDelivery.ts @@ -0,0 +1,6 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +export * from './presentationDelivery.defs.ts' +export { main as default } from './presentationDelivery.defs.ts' diff --git a/shared/lex/id/sifa/profile/project.defs.ts b/shared/lex/id/sifa/profile/project.defs.ts new file mode 100644 index 00000000..e8ea3ddf --- /dev/null +++ b/shared/lex/id/sifa/profile/project.defs.ts @@ -0,0 +1,207 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +import { l } from '@atproto/lex-schema' +import * as RepoStrongRef from '../../../com/atproto/repo/strongRef.defs.ts' +import * as SifaDefs from '../defs.defs.ts' +import * as LabelDefs from '../../../com/atproto/label/defs.defs.ts' + +const $nsid = 'id.sifa.profile.project' + +type $nsid = typeof $nsid + +export { $nsid } + +/** Record representing a single project. */ +type Main = { + $type: 'id.sifa.profile.project' + + /** + * Project name. + */ + name: string + + /** + * The user's own role on the project (e.g. 'Maintainer', 'Core contributor', 'Project lead'). Roles of other people named on the project live on members. + */ + role?: string + + /** + * Description of the project, the user's role, and outcomes. + */ + description?: string + + /** + * URL of the project (website, repository, demo, etc.). + */ + url?: l.UriString + + /** + * Reference to the first-class id.sifa.project.self record this personal entry corresponds to, when there is one. A composition link, not a peer one: for the same project recorded on someone else's profile, see sameAs. + */ + projectRef?: RepoStrongRef.Main + + /** + * Reference to the associated id.sifa.profile.position record, if applicable. + */ + position?: RepoStrongRef.Main + + /** + * The same project as recorded on another person's profile. Set when you keep your own entry for work someone else has also recorded, so consumers can tell the two describe one thing rather than showing it twice. Each side stays its own record: the other person cannot edit yours, and yours does not change theirs. Resolve by AT-URI, since they will keep editing their copy. + */ + sameAs?: SifaDefs.ExternalRecordRef + + /** + * Other people who worked on this project. Each entry is a claim by the record author and is not self-verifying: the named person supplies the other half by publishing an id.sifa.confirmation record whose subject is this record and whose relation is id.sifa.defs#projectMember. Until they do, consumers must render the entry without their display name, avatar, or profile link. Confirming never puts this record on the named person's profile: it lives in the author's repository and the author can rename it at any time. A named person who wants the project on their profile keeps their own id.sifa.profile.project record and points its projectRef here. + */ + members?: SifaDefs.ProjectMemberRef[] + + /** + * Event occurrences this project organized or hosted, for example every edition of a conference or every meetup of a series. Each entry should reference a distinct event; consumers ignore entries that don't resolve to a community.lexicon.calendar.event. A talk the user also gave at one of these events is a separate id.sifa.profile.presentationDelivery whose eventRef points at the same event. + */ + events?: ProjectEvent[] + + /** + * Project start date in YYYY-MM or YYYY-MM-DD format. + */ + startedAt?: string + + /** + * Project end date in YYYY-MM or YYYY-MM-DD format. Omit if ongoing. + */ + endedAt?: string + + /** + * Self-label values for this project record. + */ + labels?: l.$Typed | l.Unknown$TypedObject + + /** + * Whether this is the user's primary ongoing project, surfaced in profile Highlights. Only ongoing entries may be primary. + */ + isPrimary?: boolean + + /** + * Client-declared timestamp when this record was originally created. + */ + createdAt: l.DatetimeString +} + +export type { Main } + +/** Record representing a single project. */ +const main = /*#__PURE__*/ l.record<'tid', Main>( + 'tid', + $nsid, + /*#__PURE__*/ l.object({ + name: /*#__PURE__*/ l.string({ + minLength: 1, + maxGraphemes: 256, + maxLength: 2560, + }), + role: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 256, maxLength: 2560 }), + ), + description: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 5000, maxLength: 50000 }), + ), + url: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string({ format: 'uri' })), + projectRef: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => RepoStrongRef.main) as any, + ), + ), + position: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => RepoStrongRef.main) as any, + ), + ), + sameAs: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.ref( + (() => SifaDefs.externalRecordRef) as any, + ), + ), + members: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.array( + /*#__PURE__*/ l.ref( + (() => SifaDefs.projectMemberRef) as any, + ), + { maxLength: 50 }, + ), + ), + events: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.array( + /*#__PURE__*/ l.ref((() => projectEvent) as any), + { maxLength: 200 }, + ), + ), + startedAt: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string()), + endedAt: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string()), + labels: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.typedUnion( + [ + /*#__PURE__*/ l.typedRef( + (() => LabelDefs.selfLabels) as any, + ), + ], + false, + ), + ), + isPrimary: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.boolean()), + createdAt: /*#__PURE__*/ l.string({ format: 'datetime' }), + }), +) + +export { main } + +const $type = $nsid + +type $type = typeof $type + +export { $type } + +export const $isTypeOf = /*#__PURE__*/ main.isTypeOf.bind(main) +export const $build = /*#__PURE__*/ main.build.bind(main) +export const $assert = /*#__PURE__*/ main.assert.bind(main) +export const $check = /*#__PURE__*/ main.check.bind(main) +export const $cast = /*#__PURE__*/ main.cast.bind(main) +export const $ifMatches = /*#__PURE__*/ main.ifMatches.bind(main) +export const $matches = /*#__PURE__*/ main.matches.bind(main) +export const $parse = /*#__PURE__*/ main.parse.bind(main) +export const $safeParse = /*#__PURE__*/ main.safeParse.bind(main) +export const $validate = /*#__PURE__*/ main.validate.bind(main) +export const $safeValidate = /*#__PURE__*/ main.safeValidate.bind(main) + +/** One event occurrence linked to a project. */ +type ProjectEvent = { + $type?: 'id.sifa.profile.project#projectEvent' + + /** + * Reference to the community.lexicon.calendar.event. Resolve by AT-URI; the CID is an optional integrity hint. + */ + event: SifaDefs.ExternalRecordRef + + /** + * The user's role at this occurrence when it differs from the project's role (e.g. 'Organizer' for one edition, 'Host' for another). Omit to inherit project.role. + */ + role?: string +} + +export type { ProjectEvent } + +/** One event occurrence linked to a project. */ +const projectEvent = /*#__PURE__*/ l.typedObject( + $nsid, + 'projectEvent', + /*#__PURE__*/ l.object({ + event: /*#__PURE__*/ l.ref( + (() => SifaDefs.externalRecordRef) as any, + ), + role: /*#__PURE__*/ l.optional( + /*#__PURE__*/ l.string({ maxGraphemes: 64, maxLength: 640 }), + ), + }), +) + +export { projectEvent } diff --git a/shared/lex/id/sifa/profile/project.ts b/shared/lex/id/sifa/profile/project.ts new file mode 100644 index 00000000..da441a2e --- /dev/null +++ b/shared/lex/id/sifa/profile/project.ts @@ -0,0 +1,6 @@ +/* + * THIS FILE WAS GENERATED BY "@atproto/lex". DO NOT EDIT. + */ + +export * from './project.defs.ts' +export { main as default } from './project.defs.ts' diff --git a/shared/lex/index.ts b/shared/lex/index.ts index 3637291b..3c9667e7 100644 --- a/shared/lex/index.ts +++ b/shared/lex/index.ts @@ -4,4 +4,5 @@ export * as com from './com.ts' export * as community from './community.ts' +export * as id from './id.ts' export * as site from './site.ts' diff --git a/shared/project-icons.ts b/shared/project-icons.ts index 5c586251..af61f505 100644 --- a/shared/project-icons.ts +++ b/shared/project-icons.ts @@ -38,4 +38,5 @@ export const projectIcons = [ 'i-ri:toggle-line', 'i-ri:vidicon-line', 'i-ri:walk-line', + 'i-tabler:brand-nuxt', ] as const diff --git a/shared/sifa.ts b/shared/sifa.ts new file mode 100644 index 00000000..add0683c --- /dev/null +++ b/shared/sifa.ts @@ -0,0 +1,14 @@ +/** + * The Sifa profile records this site publishes. They are kept out of + * `shared/collections.ts` because that map drives the admin OAuth scopes, and + * these are only ever written by the build-time sync. + */ +import { defineCollection } from 'airspace' + +import { id } from './lex/index.ts' + +export const sifaCollections = { + presentations: defineCollection(id.sifa.profile.presentation.main), + deliveries: defineCollection(id.sifa.profile.presentationDelivery.main), + projects: defineCollection(id.sifa.profile.project.main), +} diff --git a/test/unit/sifa.spec.ts b/test/unit/sifa.spec.ts new file mode 100644 index 00000000..7cf0de95 --- /dev/null +++ b/test/unit/sifa.spec.ts @@ -0,0 +1,134 @@ +import { describe, expect, it } from 'vitest' + +import { addressFromFlag, toDelivery, toPresentation, toProject } from '../../modules/sync/providers/sifa' +import { dateFromTid, tidFromDate } from '../../modules/shared/tid' +import type { ProjectRecord, TalkRecord } from '../../shared/cms/records' + +const did = 'did:plc:jbeaa5kdaladzwq3r7f5xgwe' +const groupUri = `at://${did}/dev.roe.talkGroup/3mnhtz6v4ss2v` +const presentationUris = new Map([['3mnhtz6v4ss2v', `at://${did}/id.sifa.profile.presentation/3mnhtz6v4ss2v`]]) + +function talk (value: Partial) { + return { + rkey: '3mx3duxyit62s', + value: { + $type: 'dev.roe.talk', + date: '2026-09-24T00:00:00.000Z', + source: 'PostgreSQL Edinburgh', + type: 'meetup', + createdAt: '2026-09-24T09:32:06.462Z', + ...value, + } as TalkRecord, + } +} + +describe('addressFromFlag', () => { + it('reads a country flag', () => { + expect(addressFromFlag('🇳🇱')).toEqual({ $type: 'community.lexicon.location.address', country: 'NL' }) + }) + + it('reads a subdivision flag', () => { + expect(addressFromFlag('🏴󠁧󠁢󠁳󠁣󠁴󠁿')).toEqual({ $type: 'community.lexicon.location.address', country: 'GB', region: 'Scotland' }) + }) + + it('ignores anything else', () => { + expect(addressFromFlag('🌐')).toBeUndefined() + expect(addressFromFlag('Amsterdam')).toBeUndefined() + expect(addressFromFlag(undefined)).toBeUndefined() + }) +}) + +describe('toDelivery', () => { + it('maps a grouped conference talk', () => { + const delivery = toDelivery(talk({ + title: 'What\'s new in Nuxt 4', + type: 'conference', + source: 'Vue.js Amsterdam', + location: '🇳🇱', + group: { uri: groupUri, cid: 'bafy' } as TalkRecord['group'], + video: 'https://www.youtube.com/watch?v=abc', + slides: '2025-03-12-vuejs-amsterdam', + link: 'https://vuejs.amsterdam', + }), presentationUris) + + expect(delivery).toEqual({ + presentationRef: { uri: `at://${did}/id.sifa.profile.presentation/3mnhtz6v4ss2v` }, + title: 'What\'s new in Nuxt 4', + eventName: 'Vue.js Amsterdam', + date: '2026-09-24', + role: 'id.sifa.defs#presenter', + address: { $type: 'community.lexicon.location.address', country: 'NL' }, + links: [ + { uri: 'https://www.youtube.com/watch?v=abc', type: 'id.sifa.defs#linkRecording' }, + { uri: 'https://roe.dev/slides/2025-03-12-vuejs-amsterdam.pdf', type: 'id.sifa.defs#linkSlides' }, + { uri: 'https://vuejs.amsterdam', type: 'id.sifa.defs#linkEvent' }, + ], + createdAt: '2026-09-24T09:32:06.462Z', + }) + }) + + it('maps a podcast as a virtual delivery with no role', () => { + const delivery = toDelivery(talk({ type: 'podcast', source: 'DejaVue', link: 'https://www.youtube.com/watch?v=xyz' }), presentationUris) + + expect(delivery.role).toBeUndefined() + expect(delivery.mode).toBe('community.lexicon.calendar.event#virtual') + expect(delivery.links).toEqual([{ uri: 'https://www.youtube.com/watch?v=xyz', type: 'id.sifa.defs#linkRecording' }]) + }) + + it('maps a globe location to a virtual delivery', () => { + const delivery = toDelivery(talk({ type: 'conference', location: '🌐' }), presentationUris) + + expect(delivery.mode).toBe('community.lexicon.calendar.event#virtual') + expect(delivery.address).toBeUndefined() + }) + + it('maps a workshop role', () => { + expect(toDelivery(talk({ type: 'workshop' }), presentationUris).role).toBe('id.sifa.defs#workshop') + }) + + it('omits references to unknown groups', () => { + const delivery = toDelivery(talk({ group: { uri: `at://${did}/dev.roe.talkGroup/3aaaaaaaaaaaa`, cid: 'bafy' } as TalkRecord['group'] }), presentationUris) + + expect(delivery.presentationRef).toBeUndefined() + }) +}) + +describe('toPresentation', () => { + it('falls back to the rkey timestamp for createdAt', () => { + const rkey = tidFromDate('2025-07-04T19:16:36.000Z') + expect(toPresentation({ rkey, value: { $type: 'dev.roe.talkGroup', title: 'A new Nuxt' } })) + .toEqual({ title: 'A new Nuxt', createdAt: '2025-07-04T19:16:36.000Z' }) + }) +}) + +describe('toProject', () => { + it('prefers the website link', () => { + const project = toProject({ + rkey: '3mtxxr3iiwr26', + value: { + $type: 'dev.roe.project', + name: 'magic-regexp', + description: 'A compiled-away, type-safe, readable RegExp alternative', + category: { uri: `at://${did}/dev.roe.projectCategory/3mtxxqyu2rz26`, cid: 'bafy' }, + links: [ + { uri: 'https://github.com/unjs/magic-regexp', role: 'community.lexicon.app.defs#linkRoleSourceCode' }, + { uri: 'https://regexp.dev', role: 'community.lexicon.app.defs#linkRoleWebsite' }, + ], + createdAt: '2026-08-26T08:58:54.746Z', + } as ProjectRecord, + }) + + expect(project).toEqual({ + name: 'magic-regexp', + description: 'A compiled-away, type-safe, readable RegExp alternative', + url: 'https://regexp.dev', + createdAt: '2026-08-26T08:58:54.746Z', + }) + }) +}) + +describe('dateFromTid', () => { + it('round-trips with tidFromDate', () => { + expect(dateFromTid(tidFromDate('2019-12-10T20:18:52.000Z'))).toBe('2019-12-10T20:18:52.000Z') + }) +})